Hooray... sonews/0.5.0 final
authorchris <chris@marvin>
Fri Jun 26 16:48:50 2009 +0200 (2009-06-26)
changeset 16fceb66e1ad7
parent 0 f907866f0e4b
child 2 1090e2141798
Hooray... sonews/0.5.0 final

HG: Enter commit message. Lines beginning with 'HG:' are removed.
HG: Remove all lines to abort the collapse operation.
.hgtags
AUTHORS
COPYING
DEBIAN-web/README.Debian
DEBIAN-web/compat
DEBIAN-web/control
DEBIAN-web/docs
DEBIAN/README.Debian
DEBIAN/compat
DEBIAN/conffiles
DEBIAN/control
DEBIAN/docs
README
RFC3977
RFC3977.pdf
SConstruct
bin/sonews-web.sh
bin/sonews.sh
doc/config.xsl
doc/makedoc
doc/sonews.css
doc/sonews.xml
helpers/copyright
helpers/database_mysql5_tmpl.sql
helpers/database_postgresql8_tmpl.sql
helpers/helptext
helpers/sonews
helpers/sonews-web
helpers/sonews.conf.sample
helpers/usage
makedeb
org/sonews/daemon/AbstractDaemon.java
org/sonews/daemon/BootstrapConfig.java
org/sonews/daemon/ChannelLineBuffers.java
org/sonews/daemon/ChannelReader.java
org/sonews/daemon/ChannelWriter.java
org/sonews/daemon/Config.java
org/sonews/daemon/ConnectionWorker.java
org/sonews/daemon/Connections.java
org/sonews/daemon/LineEncoder.java
org/sonews/daemon/Main.java
org/sonews/daemon/NNTPConnection.java
org/sonews/daemon/NNTPDaemon.java
org/sonews/daemon/ShutdownHook.java
org/sonews/daemon/command/AbstractCommand.java
org/sonews/daemon/command/ArticleCommand.java
org/sonews/daemon/command/CapabilitiesCommand.java
org/sonews/daemon/command/GroupCommand.java
org/sonews/daemon/command/HelpCommand.java
org/sonews/daemon/command/ListCommand.java
org/sonews/daemon/command/ListGroupCommand.java
org/sonews/daemon/command/ModeReaderCommand.java
org/sonews/daemon/command/NewGroupsCommand.java
org/sonews/daemon/command/NextPrevCommand.java
org/sonews/daemon/command/OverCommand.java
org/sonews/daemon/command/PostCommand.java
org/sonews/daemon/command/PostState.java
org/sonews/daemon/command/QuitCommand.java
org/sonews/daemon/command/StatCommand.java
org/sonews/daemon/command/UnsupportedCommand.java
org/sonews/daemon/command/XDaemonCommand.java
org/sonews/daemon/command/XPatCommand.java
org/sonews/daemon/command/package.html
org/sonews/daemon/package.html
org/sonews/daemon/storage/Article.java
org/sonews/daemon/storage/ArticleHead.java
org/sonews/daemon/storage/Database.java
org/sonews/daemon/storage/Group.java
org/sonews/daemon/storage/Headers.java
org/sonews/daemon/storage/package.html
org/sonews/feed/AbstractFeeder.java
org/sonews/feed/FeedManager.java
org/sonews/feed/PullFeeder.java
org/sonews/feed/PushFeeder.java
org/sonews/feed/Subscription.java
org/sonews/feed/package.html
org/sonews/mlgw/Dispatcher.java
org/sonews/mlgw/MailPoller.java
org/sonews/mlgw/package.html
org/sonews/util/AbstractConfig.java
org/sonews/util/DatabaseSetup.java
org/sonews/util/Log.java
org/sonews/util/Pair.java
org/sonews/util/Purger.java
org/sonews/util/Stats.java
org/sonews/util/StringTemplate.java
org/sonews/util/TimeoutMap.java
org/sonews/util/io/ArticleInputStream.java
org/sonews/util/io/ArticleReader.java
org/sonews/util/io/ArticleWriter.java
org/sonews/util/io/Resource.java
org/sonews/util/io/VarCharsetReader.java
org/sonews/util/io/package.html
org/sonews/util/package.html
org/sonews/web/AbstractSonewsServlet.java
org/sonews/web/MemoryBitmapChart.java
org/sonews/web/SonewsChartServlet.java
org/sonews/web/SonewsConfigServlet.java
org/sonews/web/SonewsGroupServlet.java
org/sonews/web/SonewsPeerServlet.java
org/sonews/web/SonewsServlet.java
org/sonews/web/package.html
org/sonews/web/tmpl/AbstractSonewsServlet.tmpl
org/sonews/web/tmpl/ConfigUpdated.tmpl
org/sonews/web/tmpl/GroupAdded.tmpl
org/sonews/web/tmpl/GroupDeleted.tmpl
org/sonews/web/tmpl/GroupList.tmpl
org/sonews/web/tmpl/SonewsConfigServlet.tmpl
org/sonews/web/tmpl/SonewsGroupServlet.tmpl
org/sonews/web/tmpl/SonewsPeerServlet.tmpl
org/sonews/web/tmpl/SonewsServlet.tmpl
test/AbstractTest.java
test/CollectionsSpeedTest.java
test/PerfTest.java
test/PerfTestBench.java
test/StringTemplateTest.java
test/TestBench.java
test/command/ArticleTest.java
test/command/CapabilitiesTest.java
test/command/GroupTest.java
test/command/HelloQuitTest.java
test/command/ListGroupTests.java
test/command/ListTest.java
test/command/NewGroupsTest.java
test/command/NextTest.java
test/command/OverTest.java
test/command/PostTest.java
test/command/package.html
test/package.html
test/unit/DaemonTests.java
test/unit/UtilTests.java
test/unit/daemon/NNTPConnectionTest.java
test/unit/daemon/package.html
test/unit/package.html
test/unit/util/ResourceTest.java
test/unit/util/StringTemplateTest.java
test/unit/util/TimeoutMapTest.java
test/unit/util/package.html
trunk/AUTHORS
trunk/COPYING
trunk/README
trunk/TODO
trunk/com/so/news/Config.java
trunk/com/so/news/Debug.java
trunk/com/so/news/Main.java
trunk/com/so/news/NNTPConnection.java
trunk/com/so/news/NNTPDaemon.java
trunk/com/so/news/command/ArticleCommand.java
trunk/com/so/news/command/CapabilitiesCommand.java
trunk/com/so/news/command/Command.java
trunk/com/so/news/command/GroupCommand.java
trunk/com/so/news/command/ListCommand.java
trunk/com/so/news/command/ListGroupCommand.java
trunk/com/so/news/command/NewGroupsCommand.java
trunk/com/so/news/command/NextCommand.java
trunk/com/so/news/command/OverCommand.java
trunk/com/so/news/command/PostCommand.java
trunk/com/so/news/io/Resource.java
trunk/com/so/news/storage/Article.java
trunk/com/so/news/storage/Database.java
trunk/com/so/news/storage/Group.java
trunk/com/so/news/storage/Purger.java
trunk/com/so/news/util/StringTemplate.java
trunk/helpers/tbl_mysql6_tmpl.sql
trunk/rfc3977.txt
trunk/test/StringTemplateTest.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgtags	Fri Jun 26 16:48:50 2009 +0200
     1.3 @@ -0,0 +1,2 @@
     1.4 +42b394eda04ba06126b04e66606ff9ce769652fc oneThreadPerSocket
     1.5 +19130f88c6b80cbcda5626c0a49fb35b28a8e3cb sonews-0.5.0
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/AUTHORS	Fri Jun 26 16:48:50 2009 +0200
     2.3 @@ -0,0 +1,26 @@
     2.4 +AUTHORS & CREDITS
     2.5 +=================
     2.6 +
     2.7 +As most software applications "sonews" is based on the work
     2.8 +of individuals or projects. These fine people contributing to 
     2.9 +the Free Software community are mentioned here:
    2.10 +
    2.11 +sonews News Server
    2.12 +-------------------
    2.13 +Copyright (c) 2009 by Christian Lins <christian.lins@fh-osnabrueck.de>
    2.14 +
    2.15 +based partly upon
    2.16 +
    2.17 +Neat NNTP Daemon (n3tpd)
    2.18 +------------------------
    2.19 +Copyright (c) 2007, 2008 by Christian Lins <christian.lins@web.de>
    2.20 +
    2.21 +based partly upon
    2.22 +
    2.23 +tnntpd
    2.24 +------
    2.25 +Copyright (c) 2003 by Dennis Schwerdel
    2.26 +
    2.27 +If you find someone missing here, please contact the project leader!
    2.28 +
    2.29 +Thanks to Sun Microsystems for supporting this project!!
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/COPYING	Fri Jun 26 16:48:50 2009 +0200
     3.3 @@ -0,0 +1,674 @@
     3.4 +                    GNU GENERAL PUBLIC LICENSE
     3.5 +                       Version 3, 29 June 2007
     3.6 +
     3.7 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
     3.8 + Everyone is permitted to copy and distribute verbatim copies
     3.9 + of this license document, but changing it is not allowed.
    3.10 +
    3.11 +                            Preamble
    3.12 +
    3.13 +  The GNU General Public License is a free, copyleft license for
    3.14 +software and other kinds of works.
    3.15 +
    3.16 +  The licenses for most software and other practical works are designed
    3.17 +to take away your freedom to share and change the works.  By contrast,
    3.18 +the GNU General Public License is intended to guarantee your freedom to
    3.19 +share and change all versions of a program--to make sure it remains free
    3.20 +software for all its users.  We, the Free Software Foundation, use the
    3.21 +GNU General Public License for most of our software; it applies also to
    3.22 +any other work released this way by its authors.  You can apply it to
    3.23 +your programs, too.
    3.24 +
    3.25 +  When we speak of free software, we are referring to freedom, not
    3.26 +price.  Our General Public Licenses are designed to make sure that you
    3.27 +have the freedom to distribute copies of free software (and charge for
    3.28 +them if you wish), that you receive source code or can get it if you
    3.29 +want it, that you can change the software or use pieces of it in new
    3.30 +free programs, and that you know you can do these things.
    3.31 +
    3.32 +  To protect your rights, we need to prevent others from denying you
    3.33 +these rights or asking you to surrender the rights.  Therefore, you have
    3.34 +certain responsibilities if you distribute copies of the software, or if
    3.35 +you modify it: responsibilities to respect the freedom of others.
    3.36 +
    3.37 +  For example, if you distribute copies of such a program, whether
    3.38 +gratis or for a fee, you must pass on to the recipients the same
    3.39 +freedoms that you received.  You must make sure that they, too, receive
    3.40 +or can get the source code.  And you must show them these terms so they
    3.41 +know their rights.
    3.42 +
    3.43 +  Developers that use the GNU GPL protect your rights with two steps:
    3.44 +(1) assert copyright on the software, and (2) offer you this License
    3.45 +giving you legal permission to copy, distribute and/or modify it.
    3.46 +
    3.47 +  For the developers' and authors' protection, the GPL clearly explains
    3.48 +that there is no warranty for this free software.  For both users' and
    3.49 +authors' sake, the GPL requires that modified versions be marked as
    3.50 +changed, so that their problems will not be attributed erroneously to
    3.51 +authors of previous versions.
    3.52 +
    3.53 +  Some devices are designed to deny users access to install or run
    3.54 +modified versions of the software inside them, although the manufacturer
    3.55 +can do so.  This is fundamentally incompatible with the aim of
    3.56 +protecting users' freedom to change the software.  The systematic
    3.57 +pattern of such abuse occurs in the area of products for individuals to
    3.58 +use, which is precisely where it is most unacceptable.  Therefore, we
    3.59 +have designed this version of the GPL to prohibit the practice for those
    3.60 +products.  If such problems arise substantially in other domains, we
    3.61 +stand ready to extend this provision to those domains in future versions
    3.62 +of the GPL, as needed to protect the freedom of users.
    3.63 +
    3.64 +  Finally, every program is threatened constantly by software patents.
    3.65 +States should not allow patents to restrict development and use of
    3.66 +software on general-purpose computers, but in those that do, we wish to
    3.67 +avoid the special danger that patents applied to a free program could
    3.68 +make it effectively proprietary.  To prevent this, the GPL assures that
    3.69 +patents cannot be used to render the program non-free.
    3.70 +
    3.71 +  The precise terms and conditions for copying, distribution and
    3.72 +modification follow.
    3.73 +
    3.74 +                       TERMS AND CONDITIONS
    3.75 +
    3.76 +  0. Definitions.
    3.77 +
    3.78 +  "This License" refers to version 3 of the GNU General Public License.
    3.79 +
    3.80 +  "Copyright" also means copyright-like laws that apply to other kinds of
    3.81 +works, such as semiconductor masks.
    3.82 +
    3.83 +  "The Program" refers to any copyrightable work licensed under this
    3.84 +License.  Each licensee is addressed as "you".  "Licensees" and
    3.85 +"recipients" may be individuals or organizations.
    3.86 +
    3.87 +  To "modify" a work means to copy from or adapt all or part of the work
    3.88 +in a fashion requiring copyright permission, other than the making of an
    3.89 +exact copy.  The resulting work is called a "modified version" of the
    3.90 +earlier work or a work "based on" the earlier work.
    3.91 +
    3.92 +  A "covered work" means either the unmodified Program or a work based
    3.93 +on the Program.
    3.94 +
    3.95 +  To "propagate" a work means to do anything with it that, without
    3.96 +permission, would make you directly or secondarily liable for
    3.97 +infringement under applicable copyright law, except executing it on a
    3.98 +computer or modifying a private copy.  Propagation includes copying,
    3.99 +distribution (with or without modification), making available to the
   3.100 +public, and in some countries other activities as well.
   3.101 +
   3.102 +  To "convey" a work means any kind of propagation that enables other
   3.103 +parties to make or receive copies.  Mere interaction with a user through
   3.104 +a computer network, with no transfer of a copy, is not conveying.
   3.105 +
   3.106 +  An interactive user interface displays "Appropriate Legal Notices"
   3.107 +to the extent that it includes a convenient and prominently visible
   3.108 +feature that (1) displays an appropriate copyright notice, and (2)
   3.109 +tells the user that there is no warranty for the work (except to the
   3.110 +extent that warranties are provided), that licensees may convey the
   3.111 +work under this License, and how to view a copy of this License.  If
   3.112 +the interface presents a list of user commands or options, such as a
   3.113 +menu, a prominent item in the list meets this criterion.
   3.114 +
   3.115 +  1. Source Code.
   3.116 +
   3.117 +  The "source code" for a work means the preferred form of the work
   3.118 +for making modifications to it.  "Object code" means any non-source
   3.119 +form of a work.
   3.120 +
   3.121 +  A "Standard Interface" means an interface that either is an official
   3.122 +standard defined by a recognized standards body, or, in the case of
   3.123 +interfaces specified for a particular programming language, one that
   3.124 +is widely used among developers working in that language.
   3.125 +
   3.126 +  The "System Libraries" of an executable work include anything, other
   3.127 +than the work as a whole, that (a) is included in the normal form of
   3.128 +packaging a Major Component, but which is not part of that Major
   3.129 +Component, and (b) serves only to enable use of the work with that
   3.130 +Major Component, or to implement a Standard Interface for which an
   3.131 +implementation is available to the public in source code form.  A
   3.132 +"Major Component", in this context, means a major essential component
   3.133 +(kernel, window system, and so on) of the specific operating system
   3.134 +(if any) on which the executable work runs, or a compiler used to
   3.135 +produce the work, or an object code interpreter used to run it.
   3.136 +
   3.137 +  The "Corresponding Source" for a work in object code form means all
   3.138 +the source code needed to generate, install, and (for an executable
   3.139 +work) run the object code and to modify the work, including scripts to
   3.140 +control those activities.  However, it does not include the work's
   3.141 +System Libraries, or general-purpose tools or generally available free
   3.142 +programs which are used unmodified in performing those activities but
   3.143 +which are not part of the work.  For example, Corresponding Source
   3.144 +includes interface definition files associated with source files for
   3.145 +the work, and the source code for shared libraries and dynamically
   3.146 +linked subprograms that the work is specifically designed to require,
   3.147 +such as by intimate data communication or control flow between those
   3.148 +subprograms and other parts of the work.
   3.149 +
   3.150 +  The Corresponding Source need not include anything that users
   3.151 +can regenerate automatically from other parts of the Corresponding
   3.152 +Source.
   3.153 +
   3.154 +  The Corresponding Source for a work in source code form is that
   3.155 +same work.
   3.156 +
   3.157 +  2. Basic Permissions.
   3.158 +
   3.159 +  All rights granted under this License are granted for the term of
   3.160 +copyright on the Program, and are irrevocable provided the stated
   3.161 +conditions are met.  This License explicitly affirms your unlimited
   3.162 +permission to run the unmodified Program.  The output from running a
   3.163 +covered work is covered by this License only if the output, given its
   3.164 +content, constitutes a covered work.  This License acknowledges your
   3.165 +rights of fair use or other equivalent, as provided by copyright law.
   3.166 +
   3.167 +  You may make, run and propagate covered works that you do not
   3.168 +convey, without conditions so long as your license otherwise remains
   3.169 +in force.  You may convey covered works to others for the sole purpose
   3.170 +of having them make modifications exclusively for you, or provide you
   3.171 +with facilities for running those works, provided that you comply with
   3.172 +the terms of this License in conveying all material for which you do
   3.173 +not control copyright.  Those thus making or running the covered works
   3.174 +for you must do so exclusively on your behalf, under your direction
   3.175 +and control, on terms that prohibit them from making any copies of
   3.176 +your copyrighted material outside their relationship with you.
   3.177 +
   3.178 +  Conveying under any other circumstances is permitted solely under
   3.179 +the conditions stated below.  Sublicensing is not allowed; section 10
   3.180 +makes it unnecessary.
   3.181 +
   3.182 +  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
   3.183 +
   3.184 +  No covered work shall be deemed part of an effective technological
   3.185 +measure under any applicable law fulfilling obligations under article
   3.186 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
   3.187 +similar laws prohibiting or restricting circumvention of such
   3.188 +measures.
   3.189 +
   3.190 +  When you convey a covered work, you waive any legal power to forbid
   3.191 +circumvention of technological measures to the extent such circumvention
   3.192 +is effected by exercising rights under this License with respect to
   3.193 +the covered work, and you disclaim any intention to limit operation or
   3.194 +modification of the work as a means of enforcing, against the work's
   3.195 +users, your or third parties' legal rights to forbid circumvention of
   3.196 +technological measures.
   3.197 +
   3.198 +  4. Conveying Verbatim Copies.
   3.199 +
   3.200 +  You may convey verbatim copies of the Program's source code as you
   3.201 +receive it, in any medium, provided that you conspicuously and
   3.202 +appropriately publish on each copy an appropriate copyright notice;
   3.203 +keep intact all notices stating that this License and any
   3.204 +non-permissive terms added in accord with section 7 apply to the code;
   3.205 +keep intact all notices of the absence of any warranty; and give all
   3.206 +recipients a copy of this License along with the Program.
   3.207 +
   3.208 +  You may charge any price or no price for each copy that you convey,
   3.209 +and you may offer support or warranty protection for a fee.
   3.210 +
   3.211 +  5. Conveying Modified Source Versions.
   3.212 +
   3.213 +  You may convey a work based on the Program, or the modifications to
   3.214 +produce it from the Program, in the form of source code under the
   3.215 +terms of section 4, provided that you also meet all of these conditions:
   3.216 +
   3.217 +    a) The work must carry prominent notices stating that you modified
   3.218 +    it, and giving a relevant date.
   3.219 +
   3.220 +    b) The work must carry prominent notices stating that it is
   3.221 +    released under this License and any conditions added under section
   3.222 +    7.  This requirement modifies the requirement in section 4 to
   3.223 +    "keep intact all notices".
   3.224 +
   3.225 +    c) You must license the entire work, as a whole, under this
   3.226 +    License to anyone who comes into possession of a copy.  This
   3.227 +    License will therefore apply, along with any applicable section 7
   3.228 +    additional terms, to the whole of the work, and all its parts,
   3.229 +    regardless of how they are packaged.  This License gives no
   3.230 +    permission to license the work in any other way, but it does not
   3.231 +    invalidate such permission if you have separately received it.
   3.232 +
   3.233 +    d) If the work has interactive user interfaces, each must display
   3.234 +    Appropriate Legal Notices; however, if the Program has interactive
   3.235 +    interfaces that do not display Appropriate Legal Notices, your
   3.236 +    work need not make them do so.
   3.237 +
   3.238 +  A compilation of a covered work with other separate and independent
   3.239 +works, which are not by their nature extensions of the covered work,
   3.240 +and which are not combined with it such as to form a larger program,
   3.241 +in or on a volume of a storage or distribution medium, is called an
   3.242 +"aggregate" if the compilation and its resulting copyright are not
   3.243 +used to limit the access or legal rights of the compilation's users
   3.244 +beyond what the individual works permit.  Inclusion of a covered work
   3.245 +in an aggregate does not cause this License to apply to the other
   3.246 +parts of the aggregate.
   3.247 +
   3.248 +  6. Conveying Non-Source Forms.
   3.249 +
   3.250 +  You may convey a covered work in object code form under the terms
   3.251 +of sections 4 and 5, provided that you also convey the
   3.252 +machine-readable Corresponding Source under the terms of this License,
   3.253 +in one of these ways:
   3.254 +
   3.255 +    a) Convey the object code in, or embodied in, a physical product
   3.256 +    (including a physical distribution medium), accompanied by the
   3.257 +    Corresponding Source fixed on a durable physical medium
   3.258 +    customarily used for software interchange.
   3.259 +
   3.260 +    b) Convey the object code in, or embodied in, a physical product
   3.261 +    (including a physical distribution medium), accompanied by a
   3.262 +    written offer, valid for at least three years and valid for as
   3.263 +    long as you offer spare parts or customer support for that product
   3.264 +    model, to give anyone who possesses the object code either (1) a
   3.265 +    copy of the Corresponding Source for all the software in the
   3.266 +    product that is covered by this License, on a durable physical
   3.267 +    medium customarily used for software interchange, for a price no
   3.268 +    more than your reasonable cost of physically performing this
   3.269 +    conveying of source, or (2) access to copy the
   3.270 +    Corresponding Source from a network server at no charge.
   3.271 +
   3.272 +    c) Convey individual copies of the object code with a copy of the
   3.273 +    written offer to provide the Corresponding Source.  This
   3.274 +    alternative is allowed only occasionally and noncommercially, and
   3.275 +    only if you received the object code with such an offer, in accord
   3.276 +    with subsection 6b.
   3.277 +
   3.278 +    d) Convey the object code by offering access from a designated
   3.279 +    place (gratis or for a charge), and offer equivalent access to the
   3.280 +    Corresponding Source in the same way through the same place at no
   3.281 +    further charge.  You need not require recipients to copy the
   3.282 +    Corresponding Source along with the object code.  If the place to
   3.283 +    copy the object code is a network server, the Corresponding Source
   3.284 +    may be on a different server (operated by you or a third party)
   3.285 +    that supports equivalent copying facilities, provided you maintain
   3.286 +    clear directions next to the object code saying where to find the
   3.287 +    Corresponding Source.  Regardless of what server hosts the
   3.288 +    Corresponding Source, you remain obligated to ensure that it is
   3.289 +    available for as long as needed to satisfy these requirements.
   3.290 +
   3.291 +    e) Convey the object code using peer-to-peer transmission, provided
   3.292 +    you inform other peers where the object code and Corresponding
   3.293 +    Source of the work are being offered to the general public at no
   3.294 +    charge under subsection 6d.
   3.295 +
   3.296 +  A separable portion of the object code, whose source code is excluded
   3.297 +from the Corresponding Source as a System Library, need not be
   3.298 +included in conveying the object code work.
   3.299 +
   3.300 +  A "User Product" is either (1) a "consumer product", which means any
   3.301 +tangible personal property which is normally used for personal, family,
   3.302 +or household purposes, or (2) anything designed or sold for incorporation
   3.303 +into a dwelling.  In determining whether a product is a consumer product,
   3.304 +doubtful cases shall be resolved in favor of coverage.  For a particular
   3.305 +product received by a particular user, "normally used" refers to a
   3.306 +typical or common use of that class of product, regardless of the status
   3.307 +of the particular user or of the way in which the particular user
   3.308 +actually uses, or expects or is expected to use, the product.  A product
   3.309 +is a consumer product regardless of whether the product has substantial
   3.310 +commercial, industrial or non-consumer uses, unless such uses represent
   3.311 +the only significant mode of use of the product.
   3.312 +
   3.313 +  "Installation Information" for a User Product means any methods,
   3.314 +procedures, authorization keys, or other information required to install
   3.315 +and execute modified versions of a covered work in that User Product from
   3.316 +a modified version of its Corresponding Source.  The information must
   3.317 +suffice to ensure that the continued functioning of the modified object
   3.318 +code is in no case prevented or interfered with solely because
   3.319 +modification has been made.
   3.320 +
   3.321 +  If you convey an object code work under this section in, or with, or
   3.322 +specifically for use in, a User Product, and the conveying occurs as
   3.323 +part of a transaction in which the right of possession and use of the
   3.324 +User Product is transferred to the recipient in perpetuity or for a
   3.325 +fixed term (regardless of how the transaction is characterized), the
   3.326 +Corresponding Source conveyed under this section must be accompanied
   3.327 +by the Installation Information.  But this requirement does not apply
   3.328 +if neither you nor any third party retains the ability to install
   3.329 +modified object code on the User Product (for example, the work has
   3.330 +been installed in ROM).
   3.331 +
   3.332 +  The requirement to provide Installation Information does not include a
   3.333 +requirement to continue to provide support service, warranty, or updates
   3.334 +for a work that has been modified or installed by the recipient, or for
   3.335 +the User Product in which it has been modified or installed.  Access to a
   3.336 +network may be denied when the modification itself materially and
   3.337 +adversely affects the operation of the network or violates the rules and
   3.338 +protocols for communication across the network.
   3.339 +
   3.340 +  Corresponding Source conveyed, and Installation Information provided,
   3.341 +in accord with this section must be in a format that is publicly
   3.342 +documented (and with an implementation available to the public in
   3.343 +source code form), and must require no special password or key for
   3.344 +unpacking, reading or copying.
   3.345 +
   3.346 +  7. Additional Terms.
   3.347 +
   3.348 +  "Additional permissions" are terms that supplement the terms of this
   3.349 +License by making exceptions from one or more of its conditions.
   3.350 +Additional permissions that are applicable to the entire Program shall
   3.351 +be treated as though they were included in this License, to the extent
   3.352 +that they are valid under applicable law.  If additional permissions
   3.353 +apply only to part of the Program, that part may be used separately
   3.354 +under those permissions, but the entire Program remains governed by
   3.355 +this License without regard to the additional permissions.
   3.356 +
   3.357 +  When you convey a copy of a covered work, you may at your option
   3.358 +remove any additional permissions from that copy, or from any part of
   3.359 +it.  (Additional permissions may be written to require their own
   3.360 +removal in certain cases when you modify the work.)  You may place
   3.361 +additional permissions on material, added by you to a covered work,
   3.362 +for which you have or can give appropriate copyright permission.
   3.363 +
   3.364 +  Notwithstanding any other provision of this License, for material you
   3.365 +add to a covered work, you may (if authorized by the copyright holders of
   3.366 +that material) supplement the terms of this License with terms:
   3.367 +
   3.368 +    a) Disclaiming warranty or limiting liability differently from the
   3.369 +    terms of sections 15 and 16 of this License; or
   3.370 +
   3.371 +    b) Requiring preservation of specified reasonable legal notices or
   3.372 +    author attributions in that material or in the Appropriate Legal
   3.373 +    Notices displayed by works containing it; or
   3.374 +
   3.375 +    c) Prohibiting misrepresentation of the origin of that material, or
   3.376 +    requiring that modified versions of such material be marked in
   3.377 +    reasonable ways as different from the original version; or
   3.378 +
   3.379 +    d) Limiting the use for publicity purposes of names of licensors or
   3.380 +    authors of the material; or
   3.381 +
   3.382 +    e) Declining to grant rights under trademark law for use of some
   3.383 +    trade names, trademarks, or service marks; or
   3.384 +
   3.385 +    f) Requiring indemnification of licensors and authors of that
   3.386 +    material by anyone who conveys the material (or modified versions of
   3.387 +    it) with contractual assumptions of liability to the recipient, for
   3.388 +    any liability that these contractual assumptions directly impose on
   3.389 +    those licensors and authors.
   3.390 +
   3.391 +  All other non-permissive additional terms are considered "further
   3.392 +restrictions" within the meaning of section 10.  If the Program as you
   3.393 +received it, or any part of it, contains a notice stating that it is
   3.394 +governed by this License along with a term that is a further
   3.395 +restriction, you may remove that term.  If a license document contains
   3.396 +a further restriction but permits relicensing or conveying under this
   3.397 +License, you may add to a covered work material governed by the terms
   3.398 +of that license document, provided that the further restriction does
   3.399 +not survive such relicensing or conveying.
   3.400 +
   3.401 +  If you add terms to a covered work in accord with this section, you
   3.402 +must place, in the relevant source files, a statement of the
   3.403 +additional terms that apply to those files, or a notice indicating
   3.404 +where to find the applicable terms.
   3.405 +
   3.406 +  Additional terms, permissive or non-permissive, may be stated in the
   3.407 +form of a separately written license, or stated as exceptions;
   3.408 +the above requirements apply either way.
   3.409 +
   3.410 +  8. Termination.
   3.411 +
   3.412 +  You may not propagate or modify a covered work except as expressly
   3.413 +provided under this License.  Any attempt otherwise to propagate or
   3.414 +modify it is void, and will automatically terminate your rights under
   3.415 +this License (including any patent licenses granted under the third
   3.416 +paragraph of section 11).
   3.417 +
   3.418 +  However, if you cease all violation of this License, then your
   3.419 +license from a particular copyright holder is reinstated (a)
   3.420 +provisionally, unless and until the copyright holder explicitly and
   3.421 +finally terminates your license, and (b) permanently, if the copyright
   3.422 +holder fails to notify you of the violation by some reasonable means
   3.423 +prior to 60 days after the cessation.
   3.424 +
   3.425 +  Moreover, your license from a particular copyright holder is
   3.426 +reinstated permanently if the copyright holder notifies you of the
   3.427 +violation by some reasonable means, this is the first time you have
   3.428 +received notice of violation of this License (for any work) from that
   3.429 +copyright holder, and you cure the violation prior to 30 days after
   3.430 +your receipt of the notice.
   3.431 +
   3.432 +  Termination of your rights under this section does not terminate the
   3.433 +licenses of parties who have received copies or rights from you under
   3.434 +this License.  If your rights have been terminated and not permanently
   3.435 +reinstated, you do not qualify to receive new licenses for the same
   3.436 +material under section 10.
   3.437 +
   3.438 +  9. Acceptance Not Required for Having Copies.
   3.439 +
   3.440 +  You are not required to accept this License in order to receive or
   3.441 +run a copy of the Program.  Ancillary propagation of a covered work
   3.442 +occurring solely as a consequence of using peer-to-peer transmission
   3.443 +to receive a copy likewise does not require acceptance.  However,
   3.444 +nothing other than this License grants you permission to propagate or
   3.445 +modify any covered work.  These actions infringe copyright if you do
   3.446 +not accept this License.  Therefore, by modifying or propagating a
   3.447 +covered work, you indicate your acceptance of this License to do so.
   3.448 +
   3.449 +  10. Automatic Licensing of Downstream Recipients.
   3.450 +
   3.451 +  Each time you convey a covered work, the recipient automatically
   3.452 +receives a license from the original licensors, to run, modify and
   3.453 +propagate that work, subject to this License.  You are not responsible
   3.454 +for enforcing compliance by third parties with this License.
   3.455 +
   3.456 +  An "entity transaction" is a transaction transferring control of an
   3.457 +organization, or substantially all assets of one, or subdividing an
   3.458 +organization, or merging organizations.  If propagation of a covered
   3.459 +work results from an entity transaction, each party to that
   3.460 +transaction who receives a copy of the work also receives whatever
   3.461 +licenses to the work the party's predecessor in interest had or could
   3.462 +give under the previous paragraph, plus a right to possession of the
   3.463 +Corresponding Source of the work from the predecessor in interest, if
   3.464 +the predecessor has it or can get it with reasonable efforts.
   3.465 +
   3.466 +  You may not impose any further restrictions on the exercise of the
   3.467 +rights granted or affirmed under this License.  For example, you may
   3.468 +not impose a license fee, royalty, or other charge for exercise of
   3.469 +rights granted under this License, and you may not initiate litigation
   3.470 +(including a cross-claim or counterclaim in a lawsuit) alleging that
   3.471 +any patent claim is infringed by making, using, selling, offering for
   3.472 +sale, or importing the Program or any portion of it.
   3.473 +
   3.474 +  11. Patents.
   3.475 +
   3.476 +  A "contributor" is a copyright holder who authorizes use under this
   3.477 +License of the Program or a work on which the Program is based.  The
   3.478 +work thus licensed is called the contributor's "contributor version".
   3.479 +
   3.480 +  A contributor's "essential patent claims" are all patent claims
   3.481 +owned or controlled by the contributor, whether already acquired or
   3.482 +hereafter acquired, that would be infringed by some manner, permitted
   3.483 +by this License, of making, using, or selling its contributor version,
   3.484 +but do not include claims that would be infringed only as a
   3.485 +consequence of further modification of the contributor version.  For
   3.486 +purposes of this definition, "control" includes the right to grant
   3.487 +patent sublicenses in a manner consistent with the requirements of
   3.488 +this License.
   3.489 +
   3.490 +  Each contributor grants you a non-exclusive, worldwide, royalty-free
   3.491 +patent license under the contributor's essential patent claims, to
   3.492 +make, use, sell, offer for sale, import and otherwise run, modify and
   3.493 +propagate the contents of its contributor version.
   3.494 +
   3.495 +  In the following three paragraphs, a "patent license" is any express
   3.496 +agreement or commitment, however denominated, not to enforce a patent
   3.497 +(such as an express permission to practice a patent or covenant not to
   3.498 +sue for patent infringement).  To "grant" such a patent license to a
   3.499 +party means to make such an agreement or commitment not to enforce a
   3.500 +patent against the party.
   3.501 +
   3.502 +  If you convey a covered work, knowingly relying on a patent license,
   3.503 +and the Corresponding Source of the work is not available for anyone
   3.504 +to copy, free of charge and under the terms of this License, through a
   3.505 +publicly available network server or other readily accessible means,
   3.506 +then you must either (1) cause the Corresponding Source to be so
   3.507 +available, or (2) arrange to deprive yourself of the benefit of the
   3.508 +patent license for this particular work, or (3) arrange, in a manner
   3.509 +consistent with the requirements of this License, to extend the patent
   3.510 +license to downstream recipients.  "Knowingly relying" means you have
   3.511 +actual knowledge that, but for the patent license, your conveying the
   3.512 +covered work in a country, or your recipient's use of the covered work
   3.513 +in a country, would infringe one or more identifiable patents in that
   3.514 +country that you have reason to believe are valid.
   3.515 +
   3.516 +  If, pursuant to or in connection with a single transaction or
   3.517 +arrangement, you convey, or propagate by procuring conveyance of, a
   3.518 +covered work, and grant a patent license to some of the parties
   3.519 +receiving the covered work authorizing them to use, propagate, modify
   3.520 +or convey a specific copy of the covered work, then the patent license
   3.521 +you grant is automatically extended to all recipients of the covered
   3.522 +work and works based on it.
   3.523 +
   3.524 +  A patent license is "discriminatory" if it does not include within
   3.525 +the scope of its coverage, prohibits the exercise of, or is
   3.526 +conditioned on the non-exercise of one or more of the rights that are
   3.527 +specifically granted under this License.  You may not convey a covered
   3.528 +work if you are a party to an arrangement with a third party that is
   3.529 +in the business of distributing software, under which you make payment
   3.530 +to the third party based on the extent of your activity of conveying
   3.531 +the work, and under which the third party grants, to any of the
   3.532 +parties who would receive the covered work from you, a discriminatory
   3.533 +patent license (a) in connection with copies of the covered work
   3.534 +conveyed by you (or copies made from those copies), or (b) primarily
   3.535 +for and in connection with specific products or compilations that
   3.536 +contain the covered work, unless you entered into that arrangement,
   3.537 +or that patent license was granted, prior to 28 March 2007.
   3.538 +
   3.539 +  Nothing in this License shall be construed as excluding or limiting
   3.540 +any implied license or other defenses to infringement that may
   3.541 +otherwise be available to you under applicable patent law.
   3.542 +
   3.543 +  12. No Surrender of Others' Freedom.
   3.544 +
   3.545 +  If conditions are imposed on you (whether by court order, agreement or
   3.546 +otherwise) that contradict the conditions of this License, they do not
   3.547 +excuse you from the conditions of this License.  If you cannot convey a
   3.548 +covered work so as to satisfy simultaneously your obligations under this
   3.549 +License and any other pertinent obligations, then as a consequence you may
   3.550 +not convey it at all.  For example, if you agree to terms that obligate you
   3.551 +to collect a royalty for further conveying from those to whom you convey
   3.552 +the Program, the only way you could satisfy both those terms and this
   3.553 +License would be to refrain entirely from conveying the Program.
   3.554 +
   3.555 +  13. Use with the GNU Affero General Public License.
   3.556 +
   3.557 +  Notwithstanding any other provision of this License, you have
   3.558 +permission to link or combine any covered work with a work licensed
   3.559 +under version 3 of the GNU Affero General Public License into a single
   3.560 +combined work, and to convey the resulting work.  The terms of this
   3.561 +License will continue to apply to the part which is the covered work,
   3.562 +but the special requirements of the GNU Affero General Public License,
   3.563 +section 13, concerning interaction through a network will apply to the
   3.564 +combination as such.
   3.565 +
   3.566 +  14. Revised Versions of this License.
   3.567 +
   3.568 +  The Free Software Foundation may publish revised and/or new versions of
   3.569 +the GNU General Public License from time to time.  Such new versions will
   3.570 +be similar in spirit to the present version, but may differ in detail to
   3.571 +address new problems or concerns.
   3.572 +
   3.573 +  Each version is given a distinguishing version number.  If the
   3.574 +Program specifies that a certain numbered version of the GNU General
   3.575 +Public License "or any later version" applies to it, you have the
   3.576 +option of following the terms and conditions either of that numbered
   3.577 +version or of any later version published by the Free Software
   3.578 +Foundation.  If the Program does not specify a version number of the
   3.579 +GNU General Public License, you may choose any version ever published
   3.580 +by the Free Software Foundation.
   3.581 +
   3.582 +  If the Program specifies that a proxy can decide which future
   3.583 +versions of the GNU General Public License can be used, that proxy's
   3.584 +public statement of acceptance of a version permanently authorizes you
   3.585 +to choose that version for the Program.
   3.586 +
   3.587 +  Later license versions may give you additional or different
   3.588 +permissions.  However, no additional obligations are imposed on any
   3.589 +author or copyright holder as a result of your choosing to follow a
   3.590 +later version.
   3.591 +
   3.592 +  15. Disclaimer of Warranty.
   3.593 +
   3.594 +  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
   3.595 +APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
   3.596 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
   3.597 +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
   3.598 +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   3.599 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
   3.600 +IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
   3.601 +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
   3.602 +
   3.603 +  16. Limitation of Liability.
   3.604 +
   3.605 +  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   3.606 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
   3.607 +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
   3.608 +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
   3.609 +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
   3.610 +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
   3.611 +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
   3.612 +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
   3.613 +SUCH DAMAGES.
   3.614 +
   3.615 +  17. Interpretation of Sections 15 and 16.
   3.616 +
   3.617 +  If the disclaimer of warranty and limitation of liability provided
   3.618 +above cannot be given local legal effect according to their terms,
   3.619 +reviewing courts shall apply local law that most closely approximates
   3.620 +an absolute waiver of all civil liability in connection with the
   3.621 +Program, unless a warranty or assumption of liability accompanies a
   3.622 +copy of the Program in return for a fee.
   3.623 +
   3.624 +                     END OF TERMS AND CONDITIONS
   3.625 +
   3.626 +            How to Apply These Terms to Your New Programs
   3.627 +
   3.628 +  If you develop a new program, and you want it to be of the greatest
   3.629 +possible use to the public, the best way to achieve this is to make it
   3.630 +free software which everyone can redistribute and change under these terms.
   3.631 +
   3.632 +  To do so, attach the following notices to the program.  It is safest
   3.633 +to attach them to the start of each source file to most effectively
   3.634 +state the exclusion of warranty; and each file should have at least
   3.635 +the "copyright" line and a pointer to where the full notice is found.
   3.636 +
   3.637 +    <one line to give the program's name and a brief idea of what it does.>
   3.638 +    Copyright (C) <year>  <name of author>
   3.639 +
   3.640 +    This program is free software: you can redistribute it and/or modify
   3.641 +    it under the terms of the GNU General Public License as published by
   3.642 +    the Free Software Foundation, either version 3 of the License, or
   3.643 +    (at your option) any later version.
   3.644 +
   3.645 +    This program is distributed in the hope that it will be useful,
   3.646 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   3.647 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   3.648 +    GNU General Public License for more details.
   3.649 +
   3.650 +    You should have received a copy of the GNU General Public License
   3.651 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   3.652 +
   3.653 +Also add information on how to contact you by electronic and paper mail.
   3.654 +
   3.655 +  If the program does terminal interaction, make it output a short
   3.656 +notice like this when it starts in an interactive mode:
   3.657 +
   3.658 +    <program>  Copyright (C) <year>  <name of author>
   3.659 +    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   3.660 +    This is free software, and you are welcome to redistribute it
   3.661 +    under certain conditions; type `show c' for details.
   3.662 +
   3.663 +The hypothetical commands `show w' and `show c' should show the appropriate
   3.664 +parts of the General Public License.  Of course, your program's commands
   3.665 +might be different; for a GUI interface, you would use an "about box".
   3.666 +
   3.667 +  You should also get your employer (if you work as a programmer) or school,
   3.668 +if any, to sign a "copyright disclaimer" for the program, if necessary.
   3.669 +For more information on this, and how to apply and follow the GNU GPL, see
   3.670 +<http://www.gnu.org/licenses/>.
   3.671 +
   3.672 +  The GNU General Public License does not permit incorporating your program
   3.673 +into proprietary programs.  If your program is a subroutine library, you
   3.674 +may consider it more useful to permit linking proprietary applications with
   3.675 +the library.  If this is what you want to do, use the GNU Lesser General
   3.676 +Public License instead of this License.  But first, please read
   3.677 +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
   3.678 \ No newline at end of file
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/DEBIAN-web/README.Debian	Fri Jun 26 16:48:50 2009 +0200
     4.3 @@ -0,0 +1,6 @@
     4.4 +cync for Debian
     4.5 +---------------
     4.6 +
     4.7 +cync is still a very early alpha version, so be careful using it. You have been warned!
     4.8 +
     4.9 + -- Jens Mühlenhoff <jens@xerxys.org>  Mon, 11 Aug 2008 17:05:23 +0200
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/DEBIAN-web/compat	Fri Jun 26 16:48:50 2009 +0200
     5.3 @@ -0,0 +1,1 @@
     5.4 +6
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/DEBIAN-web/control	Fri Jun 26 16:48:50 2009 +0200
     6.3 @@ -0,0 +1,15 @@
     6.4 +Source: sonews
     6.5 +Section: web
     6.6 +Priority: optional
     6.7 +Maintainer: Christian Lins <cli@openoffice.org>
     6.8 +Homepage: http://www.sonews.org/
     6.9 +Package: sonews-web
    6.10 +Version: 0.5.0-beta1
    6.11 +Architecture: all
    6.12 +Depends: kitten, libjchart2d-java, sonews
    6.13 +Description: Webinterface for sonews
    6.14 + sonews is a modern Usenet server providing newsgroups via NNTP.
    6.15 + The lightweight servlet server kitten is used to provide an optional 
    6.16 + configuration web interface.
    6.17 + This metapackage depends on all required prerequisites to run the
    6.18 + servlet based webinterface of sonews.
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/DEBIAN/README.Debian	Fri Jun 26 16:48:50 2009 +0200
     7.3 @@ -0,0 +1,6 @@
     7.4 +cync for Debian
     7.5 +---------------
     7.6 +
     7.7 +cync is still a very early alpha version, so be careful using it. You have been warned!
     7.8 +
     7.9 + -- Jens Mühlenhoff <jens@xerxys.org>  Mon, 11 Aug 2008 17:05:23 +0200
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/DEBIAN/compat	Fri Jun 26 16:48:50 2009 +0200
     8.3 @@ -0,0 +1,1 @@
     8.4 +6
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/DEBIAN/conffiles	Fri Jun 26 16:48:50 2009 +0200
     9.3 @@ -0,0 +1,1 @@
     9.4 +/etc/sonews/sonews.conf
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/DEBIAN/control	Fri Jun 26 16:48:50 2009 +0200
    10.3 @@ -0,0 +1,15 @@
    10.4 +Source: sonews
    10.5 +Section: news
    10.6 +Priority: optional
    10.7 +Maintainer: Christian Lins <cli@openoffice.org>
    10.8 +Homepage: http://www.sonews.org/
    10.9 +Package: sonews
   10.10 +Version: 0.5.0
   10.11 +Architecture: all
   10.12 +Depends: openjdk-6-jre-headless | openjdk-6-jre | sun-java6-jre | cacao | jamvm, glassfish-mail, libmysql-java
   10.13 +Suggests: kitten, libpg-java, mysql-server, libjchart2d-java
   10.14 +Description: Usenet news server
   10.15 + sonews is a modern Usenet server providing newsgroups via NNTP.
   10.16 + A relational database backend is used to store the news data.
   10.17 + The lightweight servlet server kitten is used to provide an optional 
   10.18 + configuration web interface.
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/README	Fri Jun 26 16:48:50 2009 +0200
    11.3 @@ -0,0 +1,27 @@
    11.4 +sonews README
    11.5 +=============
    11.6 +
    11.7 +Prerequisites:
    11.8 +--------------
    11.9 +
   11.10 +* Java 6 Runtime or higher
   11.11 +* MySQL v5 or PostgreSQL v8 or higher
   11.12 +* JDBC driver for your database system
   11.13 +
   11.14 +
   11.15 +Installation:
   11.16 +-------------
   11.17 +
   11.18 +* Create a database in your DBMS, e.g. named like 'sonews'
   11.19 +* Create the necessary table structure using the helpers/*.sql file
   11.20 +  (you may use the experimental helper application:
   11.21 +   java -cp sonews.jar:<jdbcdriver.jar> DatabaseSetup )
   11.22 +* Customize the settings within the sonews.conf file or add config values to
   11.23 +  the 'config' table.
   11.24 +* Invoke 'bin/sonews.sh start' to start the daemon
   11.25 +
   11.26 +Bugs and other Issues:
   11.27 +----------------------
   11.28 +
   11.29 +Please mail them to christian.lins@fh-osnabrueck.de or better issue them
   11.30 +into the bugtracker at http://bugs.xerxys.info/ .
   11.31 \ No newline at end of file
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/RFC3977	Fri Jun 26 16:48:50 2009 +0200
    12.3 @@ -0,0 +1,6998 @@
    12.4 +
    12.5 +Network Working Group                                         C. Feather
    12.6 +Request for Comments: 3977                                      THUS plc
    12.7 +Obsoletes: 977                                              October 2006
    12.8 +Updates: 2980
    12.9 +Category: Standards Track
   12.10 +
   12.11 +
   12.12 +                 Network News Transfer Protocol (NNTP)
   12.13 +
   12.14 +Status of This Memo
   12.15 +
   12.16 +   This document specifies an Internet standards track protocol for the
   12.17 +   Internet community, and requests discussion and suggestions for
   12.18 +   improvements.  Please refer to the current edition of the "Internet
   12.19 +   Official Protocol Standards" (STD 1) for the standardization state
   12.20 +   and status of this protocol.  Distribution of this memo is unlimited.
   12.21 +
   12.22 +Copyright Notice
   12.23 +
   12.24 +   Copyright (C) The Internet Society (2006).
   12.25 +
   12.26 +Abstract
   12.27 +
   12.28 +   The Network News Transfer Protocol (NNTP) has been in use in the
   12.29 +   Internet for a decade, and remains one of the most popular protocols
   12.30 +   (by volume) in use today.  This document is a replacement for
   12.31 +   RFC 977, and officially updates the protocol specification.  It
   12.32 +   clarifies some vagueness in RFC 977, includes some new base
   12.33 +   functionality, and provides a specific mechanism to add standardized
   12.34 +   extensions to NNTP.
   12.35 +
   12.36 +Table of Contents
   12.37 +
   12.38 +   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .  3
   12.39 +     1.1.  Author's Note . . . . . . . . . . . . . . . . . . . . . .  4
   12.40 +   2.  Notation  . . . . . . . . . . . . . . . . . . . . . . . . . .  5
   12.41 +   3.  Basic Concepts  . . . . . . . . . . . . . . . . . . . . . . .  6
   12.42 +     3.1.  Commands and Responses  . . . . . . . . . . . . . . . . .  6
   12.43 +       3.1.1.  Multi-line Data Blocks . . . . . . . . . . . . . . . . 8
   12.44 +     3.2.  Response Codes  . . . . . . . . . . . . . . . . . . . . .  9
   12.45 +       3.2.1.  Generic Response Codes  . . . . . . . . . . . . . . . 10
   12.46 +         3.2.1.1.  Examples  . . . . . . . . . . . . . . . . . . . . 12
   12.47 +     3.3.  Capabilities and Extensions . . . . . . . . . . . . . . . 14
   12.48 +       3.3.1.  Capability Descriptions . . . . . . . . . . . . . . . 14
   12.49 +       3.3.2.  Standard Capabilities . . . . . . . . . . . . . . . . 15
   12.50 +       3.3.3.  Extensions  . . . . . . . . . . . . . . . . . . . . . 16
   12.51 +       3.3.4.  Initial IANA Register . . . . . . . . . . . . . . . . 18
   12.52 +     3.4.  Mandatory and Optional Commands . . . . . . . . . . . . . 20
   12.53 +
   12.54 +
   12.55 +
   12.56 +Feather                     Standards Track                     [Page 1]
   12.57 +
   12.58 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
   12.59 +
   12.60 +
   12.61 +       3.4.1.  Reading and Transit Servers . . . . . . . . . . . . . 21
   12.62 +       3.4.2.  Mode Switching  . . . . . . . . . . . . . . . . . . . 21
   12.63 +     3.5.  Pipelining  . . . . . . . . . . . . . . . . . . . . . . . 22
   12.64 +       3.5.1.  Examples  . . . . . . . . . . . . . . . . . . . . . . 23
   12.65 +     3.6.  Articles  . . . . . . . . . . . . . . . . . . . . . . . . 24
   12.66 +   4.  The WILDMAT Format  . . . . . . . . . . . . . . . . . . . . . 25
   12.67 +     4.1.  Wildmat Syntax  . . . . . . . . . . . . . . . . . . . . . 26
   12.68 +     4.2.  Wildmat Semantics . . . . . . . . . . . . . . . . . . . . 26
   12.69 +     4.3.  Extensions  . . . . . . . . . . . . . . . . . . . . . . . 27
   12.70 +     4.4.  Examples  . . . . . . . . . . . . . . . . . . . . . . . . 27
   12.71 +   5.  Session Administration Commands . . . . . . . . . . . . . . . 28
   12.72 +     5.1.  Initial Connection  . . . . . . . . . . . . . . . . . . . 28
   12.73 +     5.2.  CAPABILITIES  . . . . . . . . . . . . . . . . . . . . . . 29
   12.74 +     5.3.  MODE READER . . . . . . . . . . . . . . . . . . . . . . . 32
   12.75 +     5.4.  QUIT  . . . . . . . . . . . . . . . . . . . . . . . . . . 34
   12.76 +   6.  Article Posting and Retrieval . . . . . . . . . . . . . . . . 35
   12.77 +     6.1.  Group and Article Selection . . . . . . . . . . . . . . . 36
   12.78 +       6.1.1.  GROUP . . . . . . . . . . . . . . . . . . . . . . . . 36
   12.79 +       6.1.2.  LISTGROUP . . . . . . . . . . . . . . . . . . . . . . 39
   12.80 +       6.1.3.  LAST  . . . . . . . . . . . . . . . . . . . . . . . . 42
   12.81 +       6.1.4.  NEXT  . . . . . . . . . . . . . . . . . . . . . . . . 44
   12.82 +     6.2.  Retrieval of Articles and Article Sections  . . . . . . . 45
   12.83 +       6.2.1.  ARTICLE . . . . . . . . . . . . . . . . . . . . . . . 46
   12.84 +       6.2.2.  HEAD  . . . . . . . . . . . . . . . . . . . . . . . . 49
   12.85 +       6.2.3.  BODY  . . . . . . . . . . . . . . . . . . . . . . . . 51
   12.86 +       6.2.4.  STAT  . . . . . . . . . . . . . . . . . . . . . . . . 53
   12.87 +     6.3.  Article Posting . . . . . . . . . . . . . . . . . . . . . 56
   12.88 +       6.3.1.  POST  . . . . . . . . . . . . . . . . . . . . . . . . 56
   12.89 +       6.3.2.  IHAVE . . . . . . . . . . . . . . . . . . . . . . . . 58
   12.90 +   7.  Information Commands  . . . . . . . . . . . . . . . . . . . . 61
   12.91 +     7.1.  DATE  . . . . . . . . . . . . . . . . . . . . . . . . . . 61
   12.92 +     7.2.  HELP  . . . . . . . . . . . . . . . . . . . . . . . . . . 62
   12.93 +     7.3.  NEWGROUPS . . . . . . . . . . . . . . . . . . . . . . . . 63
   12.94 +     7.4.  NEWNEWS . . . . . . . . . . . . . . . . . . . . . . . . . 64
   12.95 +     7.5.  Time  . . . . . . . . . . . . . . . . . . . . . . . . . . 65
   12.96 +       7.5.1.  Examples  . . . . . . . . . . . . . . . . . . . . . . 66
   12.97 +     7.6.  The LIST Commands . . . . . . . . . . . . . . . . . . . . 66
   12.98 +       7.6.1.  LIST  . . . . . . . . . . . . . . . . . . . . . . . . 67
   12.99 +       7.6.2.  Standard LIST Keywords  . . . . . . . . . . . . . . . 69
  12.100 +       7.6.3.  LIST ACTIVE . . . . . . . . . . . . . . . . . . . . . 70
  12.101 +       7.6.4.  LIST ACTIVE.TIMES . . . . . . . . . . . . . . . . . . 71
  12.102 +       7.6.5.  LIST DISTRIB.PATS . . . . . . . . . . . . . . . . . . 72
  12.103 +       7.6.6.  LIST NEWSGROUPS . . . . . . . . . . . . . . . . . . . 73
  12.104 +   8.  Article Field Access Commands . . . . . . . . . . . . . . . . 73
  12.105 +     8.1.  Article Metadata  . . . . . . . . . . . . . . . . . . . . 74
  12.106 +       8.1.1.  The :bytes Metadata Item  . . . . . . . . . . . . . . 74
  12.107 +       8.1.2.  The :lines Metadata Item  . . . . . . . . . . . . . . 75
  12.108 +     8.2.  Database Consistency  . . . . . . . . . . . . . . . . . . 75
  12.109 +
  12.110 +
  12.111 +
  12.112 +Feather                     Standards Track                     [Page 2]
  12.113 +
  12.114 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.115 +
  12.116 +
  12.117 +     8.3.  OVER  . . . . . . . . . . . . . . . . . . . . . . . . . . 76
  12.118 +     8.4.  LIST OVERVIEW.FMT . . . . . . . . . . . . . . . . . . . . 81
  12.119 +     8.5.  HDR . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
  12.120 +     8.6.  LIST HEADERS  . . . . . . . . . . . . . . . . . . . . . . 87
  12.121 +   9.  Augmented BNF Syntax for NNTP . . . . . . . . . . . . . . . . 90
  12.122 +     9.1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . 90
  12.123 +     9.2.  Commands  . . . . . . . . . . . . . . . . . . . . . . . . 92
  12.124 +     9.3.  Command Continuation  . . . . . . . . . . . . . . . . . . 93
  12.125 +     9.4.  Responses . . . . . . . . . . . . . . . . . . . . . . . . 93
  12.126 +       9.4.1.  Generic Responses . . . . . . . . . . . . . . . . . . 93
  12.127 +       9.4.2.  Initial Response Line Contents  . . . . . . . . . . . 94
  12.128 +       9.4.3.  Multi-line Response Contents  . . . . . . . . . . . . 94
  12.129 +     9.5.  Capability Lines  . . . . . . . . . . . . . . . . . . . . 95
  12.130 +     9.6.  LIST Variants . . . . . . . . . . . . . . . . . . . . . . 96
  12.131 +     9.7.  Articles  . . . . . . . . . . . . . . . . . . . . . . . . 97
  12.132 +     9.8.  General Non-terminals . . . . . . . . . . . . . . . . . . 97
  12.133 +     9.9.  Extensions and Validation . . . . . . . . . . . . . . . . 99
  12.134 +   10. Internationalisation Considerations . . . . . . . . . . . . .100
  12.135 +     10.1. Introduction and Historical Situation . . . . . . . . . .100
  12.136 +     10.2. This Specification  . . . . . . . . . . . . . . . . . . .101
  12.137 +     10.3. Outstanding Issues  . . . . . . . . . . . . . . . . . . .102
  12.138 +   11. IANA Considerations . . . . . . . . . . . . . . . . . . . . .103
  12.139 +   12. Security Considerations . . . . . . . . . . . . . . . . . . .103
  12.140 +     12.1. Personal and Proprietary Information  . . . . . . . . . .104
  12.141 +     12.2. Abuse of Server Log Information . . . . . . . . . . . . .104
  12.142 +     12.3. Weak Authentication and Access Control  . . . . . . . . .104
  12.143 +     12.4. DNS Spoofing  . . . . . . . . . . . . . . . . . . . . . .104
  12.144 +     12.5. UTF-8 Issues  . . . . . . . . . . . . . . . . . . . . . .105
  12.145 +     12.6. Caching of Capability Lists . . . . . . . . . . . . . . .106
  12.146 +   13. Acknowledgements  . . . . . . . . . . . . . . . . . . . . . .107
  12.147 +   14. References  . . . . . . . . . . . . . . . . . . . . . . . . .110
  12.148 +     14.1. Normative References  . . . . . . . . . . . . . . . . . .110
  12.149 +     14.2. Informative References  . . . . . . . . . . . . . . . . .110
  12.150 +   A.  Interaction with Other Specifications . . . . . . . . . . . .112
  12.151 +     A.1.  Header Folding  . . . . . . . . . . . . . . . . . . . . .112
  12.152 +     A.2.  Message-IDs . . . . . . . . . . . . . . . . . . . . . . .112
  12.153 +     A.3.  Article Posting . . . . . . . . . . . . . . . . . . . . .114
  12.154 +   B.  Summary of Commands . . . . . . . . . . . . . . . . . . . . .115
  12.155 +   C.  Summary of Response Codes . . . . . . . . . . . . . . . . . .117
  12.156 +   D.  Changes from RFC 977  . . . . . . . . . . . . . . . . . . . .121
  12.157 +
  12.158 +1.  Introduction
  12.159 +
  12.160 +   This document specifies the Network News Transfer Protocol (NNTP),
  12.161 +   which is used for the distribution, inquiry, retrieval, and posting
  12.162 +   of Netnews articles using a reliable stream-based mechanism.  For
  12.163 +   news-reading clients, NNTP enables retrieval of news articles that
  12.164 +
  12.165 +
  12.166 +
  12.167 +
  12.168 +Feather                     Standards Track                     [Page 3]
  12.169 +
  12.170 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.171 +
  12.172 +
  12.173 +   are stored in a central database, giving subscribers the ability to
  12.174 +   select only those articles they wish to read.
  12.175 +
  12.176 +   The Netnews model provides for indexing, cross-referencing, and
  12.177 +   expiration of aged messages.  NNTP is designed for efficient
  12.178 +   transmission of Netnews articles over a reliable full duplex
  12.179 +   communication channel.
  12.180 +
  12.181 +   Although the protocol specification in this document is largely
  12.182 +   compatible with the version specified in RFC 977 [RFC977], a number
  12.183 +   of changes are summarised in Appendix D.  In particular:
  12.184 +
  12.185 +   o  the default character set is changed from US-ASCII [ANSI1986] to
  12.186 +      UTF-8 [RFC3629] (note that US-ASCII is a subset of UTF-8);
  12.187 +
  12.188 +   o  a number of commands that were optional in RFC 977 or that have
  12.189 +      been taken from RFC 2980 [RFC2980] are now mandatory; and
  12.190 +
  12.191 +   o  a CAPABILITIES command has been added to allow clients to
  12.192 +      determine what functionality is available from a server.
  12.193 +
  12.194 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  12.195 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  12.196 +   document are to be interpreted as described in RFC 2119 [RFC2119].
  12.197 +
  12.198 +   An implementation is not compliant if it fails to satisfy one or more
  12.199 +   of the MUST requirements for this protocol.  An implementation that
  12.200 +   satisfies all the MUST and all the SHOULD requirements for its
  12.201 +   protocols is said to be "unconditionally compliant"; one that
  12.202 +   satisfies all the MUST requirements but not all the SHOULD
  12.203 +   requirements for NNTP is said to be "conditionally compliant".
  12.204 +
  12.205 +   For the remainder of this document, the terms "client" and "client
  12.206 +   host" refer to a host making use of the NNTP service, while the terms
  12.207 +   "server" and "server host" refer to a host that offers the NNTP
  12.208 +   service.
  12.209 +
  12.210 +1.1.  Author's Note
  12.211 +
  12.212 +   This document is written in XML using an NNTP-specific DTD.  Custom
  12.213 +   software is used to convert this to RFC 2629 [RFC2629] format, and
  12.214 +   then the public "xml2rfc" package to further reduce this to text,
  12.215 +   nroff source, and HTML.
  12.216 +
  12.217 +   No perl was used in producing this document.
  12.218 +
  12.219 +
  12.220 +
  12.221 +
  12.222 +
  12.223 +
  12.224 +Feather                     Standards Track                     [Page 4]
  12.225 +
  12.226 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.227 +
  12.228 +
  12.229 +2.  Notation
  12.230 +
  12.231 +   The following notational conventions are used in this document.
  12.232 +
  12.233 +     UPPERCASE     indicates literal text to be included in the
  12.234 +                   command.
  12.235 +
  12.236 +     lowercase     indicates a token described elsewhere.
  12.237 +
  12.238 +     [brackets]    indicate that the enclosed material is optional.
  12.239 +
  12.240 +     elliptical    indicates that the argument may be repeated any
  12.241 +     ... marks     number of times (it must occur at least once).
  12.242 +
  12.243 +     vertical|bar  indicates a choice of two mutually exclusive
  12.244 +                   arguments (exactly one must be provided).
  12.245 +
  12.246 +   The name "message-id" for a command or response argument indicates
  12.247 +   that it is the message-id of an article as described in Section 3.6,
  12.248 +   including the angle brackets.
  12.249 +
  12.250 +   The name "wildmat" for an argument indicates that it is a wildmat as
  12.251 +   defined in Section 4.  If the argument does not meet the requirements
  12.252 +   of that section (for example, if it does not fit the grammar of
  12.253 +   Section 4.1), the NNTP server MAY place some interpretation on it
  12.254 +   (not specified by this document) or otherwise MUST treat it as a
  12.255 +   syntax error.
  12.256 +
  12.257 +   Responses for each command will be described in tables listing the
  12.258 +   required format of a response followed by the meaning that should be
  12.259 +   ascribed to that response.
  12.260 +
  12.261 +   The terms "NUL", "TAB", "LF", "CR, and "space" refer to the octets
  12.262 +   %x00, %x09, %x0A, %x0D, and %x20, respectively (that is, the octets
  12.263 +   with those codes in US-ASCII [ANSI1986] and thus in UTF-8 [RFC3629]).
  12.264 +   The term "CRLF" or "CRLF pair" means the sequence CR immediately
  12.265 +   followed by LF (that is, %x0D.0A).  A "printable US-ASCII character"
  12.266 +   is an octet in the range %x21-7E.  Quoted characters refer to the
  12.267 +   octets with those codes in US-ASCII (so "." and "<" refer to %x2E and
  12.268 +   %x3C) and will always be printable US-ASCII characters; similarly,
  12.269 +   "digit" refers to the octets %x30-39.
  12.270 +
  12.271 +   A "keyword" MUST consist only of US-ASCII letters, digits, and the
  12.272 +   characters dot (".") and dash ("-") and MUST begin with a letter.
  12.273 +   Keywords MUST be at least three characters in length.
  12.274 +
  12.275 +
  12.276 +
  12.277 +
  12.278 +
  12.279 +
  12.280 +Feather                     Standards Track                     [Page 5]
  12.281 +
  12.282 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.283 +
  12.284 +
  12.285 +   Examples in this document are not normative but serve to illustrate
  12.286 +   usages, arguments, and responses.  In the examples, a "[C]" will be
  12.287 +   used to represent the client host and an "[S]" will be used to
  12.288 +   represent the server host.  Most of the examples do not rely on a
  12.289 +   particular server state.  In some cases, however, they do assume that
  12.290 +   the currently selected newsgroup (see the GROUP command,
  12.291 +   Section 6.1.1) is invalid; when so, this is indicated at the start of
  12.292 +   the example.  Examples may use commands or other keywords not defined
  12.293 +   in this specification (such as an XENCRYPT command).  These will be
  12.294 +   used to illustrate some point and do not imply that any such command
  12.295 +   is defined elsewhere or needs to exist in any particular
  12.296 +   implementation.
  12.297 +
  12.298 +   Terms that might be read as specifying details of a client or server
  12.299 +   implementation, such as "database", are used simply to ease
  12.300 +   description.  Provided that implementations conform to the protocol
  12.301 +   and format specifications in this document, no specific technique is
  12.302 +   mandated.
  12.303 +
  12.304 +3.  Basic Concepts
  12.305 +
  12.306 +3.1.  Commands and Responses
  12.307 +
  12.308 +   NNTP operates over any reliable bi-directional 8-bit-wide data stream
  12.309 +   channel.  When the connection is established, the NNTP server host
  12.310 +   MUST send a greeting.  The client host and server host then exchange
  12.311 +   commands and responses (respectively) until the connection is closed
  12.312 +   or aborted.  If the connection used is TCP, then the server host
  12.313 +   starts the NNTP service by listening on a TCP port.  When a client
  12.314 +   host wishes to make use of the service, it MUST establish a TCP
  12.315 +   connection with the server host by connecting to that host on the
  12.316 +   same port on which the server is listening.
  12.317 +
  12.318 +   The character set for all NNTP commands is UTF-8 [RFC3629].  Commands
  12.319 +   in NNTP MUST consist of a keyword, which MAY be followed by one or
  12.320 +   more arguments.  A CRLF pair MUST terminate all commands.  Multiple
  12.321 +   commands MUST NOT be on the same line.  Unless otherwise noted
  12.322 +   elsewhere in this document, arguments SHOULD consist of printable US-
  12.323 +   ASCII characters.  Keywords and arguments MUST each be separated by
  12.324 +   one or more space or TAB characters.  Command lines MUST NOT exceed
  12.325 +   512 octets, which includes the terminating CRLF pair.  The arguments
  12.326 +   MUST NOT exceed 497 octets.  A server MAY relax these limits for
  12.327 +   commands defined in an extension.
  12.328 +
  12.329 +   Where this specification permits UTF-8 characters outside the range
  12.330 +   of U+0000 to U+007F, implementations MUST NOT use the Byte Order Mark
  12.331 +   (U+FEFF, encoding %xEF.BB.BF) and MUST use the Word Joiner (U+2060,
  12.332 +   encoding %xE2.91.A0) for the meaning Zero Width No-Break Space in
  12.333 +
  12.334 +
  12.335 +
  12.336 +Feather                     Standards Track                     [Page 6]
  12.337 +
  12.338 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.339 +
  12.340 +
  12.341 +   command lines and the initial lines of responses.  Implementations
  12.342 +   SHOULD apply these same principles throughout.
  12.343 +
  12.344 +   The term "character" means a single Unicode code point.
  12.345 +   Implementations are not required to carry out Unicode normalisation.
  12.346 +   Thus, U+0084 (A-dieresis) is one character, while U+0041 U+0308 (A
  12.347 +   composed with dieresis) is two; the two need not be treated as
  12.348 +   equivalent.
  12.349 +
  12.350 +   Commands may have variants; if so, they use a second keyword
  12.351 +   immediately after the first to indicate which variant is required.
  12.352 +   The only such commands in this specification are LIST and MODE.  Note
  12.353 +   that such variants are sometimes referred to as if they were commands
  12.354 +   in their own right: "the LIST ACTIVE" command should be read as
  12.355 +   shorthand for "the ACTIVE variant of the LIST command".
  12.356 +
  12.357 +   Keywords are case insensitive; the case of keywords for commands MUST
  12.358 +   be ignored by the server.  Command and response arguments are case or
  12.359 +   language specific only when stated, either in this document or in
  12.360 +   other relevant specifications.
  12.361 +
  12.362 +   In some cases, a command involves more data than just a single line.
  12.363 +   The further data may be sent either immediately after the command
  12.364 +   line (there are no instances of this in this specification, but there
  12.365 +   are in extensions such as [NNTP-STREAM]) or following a request from
  12.366 +   the server (indicated by a 3xx response).
  12.367 +
  12.368 +   Each response MUST start with a three-digit response code that is
  12.369 +   sufficient to distinguish all responses.  Certain valid responses are
  12.370 +   defined to be multi-line; for all others, the response is contained
  12.371 +   in a single line.  The initial line of the response MUST NOT exceed
  12.372 +   512 octets, which includes the response code and the terminating CRLF
  12.373 +   pair; an extension MAY specify a greater maximum for commands that it
  12.374 +   defines, but not for any other command.  Single-line responses
  12.375 +   consist of an initial line only.  Multi-line responses consist of an
  12.376 +   initial line followed by a multi-line data block.
  12.377 +
  12.378 +   An NNTP server MAY have an inactivity autologout timer.  Such a timer
  12.379 +   SHOULD be of at least three minutes' duration, with the exception
  12.380 +   that there MAY be a shorter limit on how long the server is willing
  12.381 +   to wait for the first command from the client.  The receipt of any
  12.382 +   command from the client during the timer interval SHOULD suffice to
  12.383 +   reset the autologout timer.  Similarly, the receipt of any
  12.384 +   significant amount of data from a client that is sending a multi-line
  12.385 +   data block (such as during a POST or IHAVE command) SHOULD suffice to
  12.386 +   reset the autologout timer.  When the timer expires, the server
  12.387 +   SHOULD close the connection without sending any response to the
  12.388 +   client.
  12.389 +
  12.390 +
  12.391 +
  12.392 +Feather                     Standards Track                     [Page 7]
  12.393 +
  12.394 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.395 +
  12.396 +
  12.397 +3.1.1.  Multi-line Data Blocks
  12.398 +
  12.399 +   A multi-line data block is used in certain commands and responses.
  12.400 +   It MUST adhere to the following rules:
  12.401 +
  12.402 +   1.  The block consists of a sequence of zero or more "lines", each
  12.403 +       being a stream of octets ending with a CRLF pair.  Apart from
  12.404 +       those line endings, the stream MUST NOT include the octets NUL,
  12.405 +       LF, or CR.
  12.406 +
  12.407 +   2.  In a multi-line response, the block immediately follows the CRLF
  12.408 +       at the end of the initial line of the response.  When used in any
  12.409 +       other context, the specific command will define when the block is
  12.410 +       sent.
  12.411 +
  12.412 +   3.  If any line of the data block begins with the "termination octet"
  12.413 +       ("." or %x2E), that line MUST be "dot-stuffed" by prepending an
  12.414 +       additional termination octet to that line of the block.
  12.415 +
  12.416 +   4.  The lines of the block MUST be followed by a terminating line
  12.417 +       consisting of a single termination octet followed by a CRLF pair
  12.418 +       in the normal way.  Thus, unless it is empty, a multi-line block
  12.419 +       is always terminated with the five octets CRLF "." CRLF
  12.420 +       (%x0D.0A.2E.0D.0A).
  12.421 +
  12.422 +   5.  When a multi-line block is interpreted, the "dot-stuffing" MUST
  12.423 +       be undone; i.e., the recipient MUST ensure that, in any line
  12.424 +       beginning with the termination octet followed by octets other
  12.425 +       than a CRLF pair, that initial termination octet is disregarded.
  12.426 +
  12.427 +   6.  Likewise, the terminating line ("." CRLF or %x2E.0D.0A) MUST NOT
  12.428 +       be considered part of the multi-line block; i.e., the recipient
  12.429 +       MUST ensure that any line beginning with the termination octet
  12.430 +       followed immediately by a CRLF pair is disregarded.  (The first
  12.431 +       CRLF pair of the terminating CRLF "." CRLF of a non-empty block
  12.432 +       is, of course, part of the last line of the block.)
  12.433 +
  12.434 +   Note that texts using an encoding (such as UTF-16 or UTF-32) that may
  12.435 +   contain the octets NUL, LF, or CR other than a CRLF pair cannot be
  12.436 +   reliably conveyed in the above format (that is, they violate the MUST
  12.437 +   requirement above).  However, except when stated otherwise, this
  12.438 +   specification does not require the content to be UTF-8, and therefore
  12.439 +   (subject to that same requirement) it MAY include octets above and
  12.440 +   below 128 mixed arbitrarily.
  12.441 +
  12.442 +   This document does not place any limit on the length of a line in a
  12.443 +   multi-line block.  However, the standards that define the format of
  12.444 +   articles may do so.
  12.445 +
  12.446 +
  12.447 +
  12.448 +Feather                     Standards Track                     [Page 8]
  12.449 +
  12.450 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.451 +
  12.452 +
  12.453 +3.2.  Response Codes
  12.454 +
  12.455 +   Each response MUST begin with a three-digit status indicator.  These
  12.456 +   are status reports from the server and indicate the response to the
  12.457 +   last command received from the client.
  12.458 +
  12.459 +   The first digit of the response broadly indicates the success,
  12.460 +   failure, or progress of the previous command:
  12.461 +
  12.462 +      1xx - Informative message
  12.463 +      2xx - Command completed OK
  12.464 +      3xx - Command OK so far; send the rest of it
  12.465 +      4xx - Command was syntactically correct but failed for some reason
  12.466 +      5xx - Command unknown, unsupported, unavailable, or syntax error
  12.467 +
  12.468 +   The next digit in the code indicates the function response category:
  12.469 +
  12.470 +      x0x - Connection, setup, and miscellaneous messages
  12.471 +      x1x - Newsgroup selection
  12.472 +      x2x - Article selection
  12.473 +      x3x - Distribution functions
  12.474 +      x4x - Posting
  12.475 +      x8x - Reserved for authentication and privacy extensions
  12.476 +      x9x - Reserved for private use (non-standard extensions)
  12.477 +
  12.478 +   Certain responses contain arguments such as numbers and names in
  12.479 +   addition to the status indicator.  In those cases, to simplify
  12.480 +   interpretation by the client, the number and type of such arguments
  12.481 +   is fixed for each response code, as is whether the code is
  12.482 +   single-line or multi-line.  Any extension MUST follow this principle
  12.483 +   as well.  Note that, for historical reasons, the 211 response code is
  12.484 +   an exception to this in that the response may be single-line or
  12.485 +   multi-line depending on the command (GROUP or LISTGROUP) that
  12.486 +   generated it.  In all other cases, the client MUST only use the
  12.487 +   status indicator itself to determine the nature of the response.  The
  12.488 +   exact response codes that can be returned by any given command are
  12.489 +   detailed in the description of that command.
  12.490 +
  12.491 +   Arguments MUST be separated from the numeric status indicator and
  12.492 +   from each other by a single space.  All numeric arguments MUST be in
  12.493 +   base 10 (decimal) format and MAY have leading zeros.  String
  12.494 +   arguments MUST contain at least one character and MUST NOT contain
  12.495 +   TAB, LF, CR, or space.  The server MAY add any text after the
  12.496 +   response code or last argument, as appropriate, and the client MUST
  12.497 +   NOT make decisions based on this text.  Such text MUST be separated
  12.498 +   from the numeric status indicator or the last argument by at least
  12.499 +   one space.
  12.500 +
  12.501 +
  12.502 +
  12.503 +
  12.504 +Feather                     Standards Track                     [Page 9]
  12.505 +
  12.506 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.507 +
  12.508 +
  12.509 +   The server MUST respond to any command with the appropriate generic
  12.510 +   response (given in Section 3.2.1) if it represents the situation.
  12.511 +   Otherwise, each recognized command MUST return one of the response
  12.512 +   codes specifically listed in its description or in an extension.  A
  12.513 +   server MAY provide extensions to this specification, including new
  12.514 +   commands, new variants or features of existing commands, and other
  12.515 +   ways of changing the internal state of the server.  However, the
  12.516 +   server MUST NOT produce any other responses to a client that does not
  12.517 +   invoke any of the additional features.  (Therefore, a client that
  12.518 +   restricts itself to this specification will only receive the
  12.519 +   responses that are listed.)
  12.520 +
  12.521 +   If a client receives an unexpected response, it SHOULD use the first
  12.522 +   digit of the response to determine the result.  For example, an
  12.523 +   unexpected 2xx should be taken as success, and an unexpected 4xx or
  12.524 +   5xx as failure.
  12.525 +
  12.526 +   Response codes not specified in this document MAY be used for any
  12.527 +   installation-specific additional commands also not specified.  These
  12.528 +   SHOULD be chosen to fit the pattern of x9x specified above.
  12.529 +
  12.530 +   Neither this document nor any registered extension (see
  12.531 +   Section 3.3.3) will specify any response codes of the x9x pattern.
  12.532 +   (Implementers of extensions are accordingly cautioned not to use such
  12.533 +   responses for extensions that may subsequently be submitted for
  12.534 +   registration.)
  12.535 +
  12.536 +3.2.1.  Generic Response Codes
  12.537 +
  12.538 +   The server MUST respond to any command with the appropriate one of
  12.539 +   the following generic responses if it represents the situation.
  12.540 +
  12.541 +   If the command is not recognized, or if it is an optional command
  12.542 +   that is not implemented by the server, the response code 500 MUST be
  12.543 +   returned.
  12.544 +
  12.545 +   If there is a syntax error in the arguments of a recognized command,
  12.546 +   including the case where more arguments are provided than the command
  12.547 +   specifies or the command line is longer than the server accepts, the
  12.548 +   response code 501 MUST be returned.  The line MUST NOT be truncated
  12.549 +   or split and then interpreted.  Note that where a command has
  12.550 +   variants depending on a second keyword (e.g., LIST ACTIVE and LIST
  12.551 +   NEWSGROUPS), 501 MUST be used when the base command is implemented
  12.552 +   but the requested variant is not, and 500 MUST be used only when the
  12.553 +   base command itself is not implemented.
  12.554 +
  12.555 +   If an argument is required to be a base64-encoded string [RFC4648]
  12.556 +   (there are no such arguments in this specification, but there may be
  12.557 +
  12.558 +
  12.559 +
  12.560 +Feather                     Standards Track                    [Page 10]
  12.561 +
  12.562 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.563 +
  12.564 +
  12.565 +   in extensions) and is not validly encoded, the response code 504 MUST
  12.566 +   be returned.
  12.567 +
  12.568 +   If the server experiences an internal fault or problem that means it
  12.569 +   is unable to carry out the command (for example, a necessary file is
  12.570 +   missing or a necessary service could not be contacted), the response
  12.571 +   code 403 MUST be returned.  If the server recognizes the command but
  12.572 +   does not provide an optional feature (for example, because it does
  12.573 +   not store the required information), or if it only handles a subset
  12.574 +   of legitimate cases (see the HDR command, Section 8.5, for an
  12.575 +   example), the response code 503 MUST be returned.
  12.576 +
  12.577 +   If the client is not authorized to use the specified facility when
  12.578 +   the server is in its current state, then the appropriate one of the
  12.579 +   following response codes MUST be used.
  12.580 +
  12.581 +   502: It is necessary to terminate the connection and to start a new
  12.582 +      one with the appropriate authority before the command can be used.
  12.583 +      Historically, some mode-switching servers (see Section 3.4.1) used
  12.584 +      this response to indicate that this command will become available
  12.585 +      after the MODE READER command (Section 5.3) is used, but this
  12.586 +      usage does not conform to this specification and MUST NOT be used.
  12.587 +      Note that the server MUST NOT close the connection immediately
  12.588 +      after a 502 response except at the initial connection
  12.589 +      (Section 5.1) and with the MODE READER command.
  12.590 +
  12.591 +   480: The client must authenticate itself to the server (that is, it
  12.592 +      must provide information as to the identity of the client) before
  12.593 +      the facility can be used on this connection.  This will involve
  12.594 +      the use of an authentication extension such as [NNTP-AUTH].
  12.595 +
  12.596 +   483: The client must negotiate appropriate privacy protection on the
  12.597 +      connection.  This will involve the use of a privacy extension such
  12.598 +      as [NNTP-TLS].
  12.599 +
  12.600 +   401: The client must change the state of the connection in some other
  12.601 +      manner.  The first argument of the response MUST be the capability
  12.602 +      label (see Section 5.2) of the facility that provides the
  12.603 +      necessary mechanism (usually an extension, which may be a private
  12.604 +      extension).  The server MUST NOT use this response code except as
  12.605 +      specified by the definition of the capability in question.
  12.606 +
  12.607 +   If the server has to terminate the connection for some reason, it
  12.608 +   MUST give a 400 response code to the next command and then
  12.609 +   immediately close the connection.  Following a 400 response, clients
  12.610 +   SHOULD NOT simply reconnect immediately and retry the same actions.
  12.611 +   Rather, a client SHOULD either use an exponentially increasing delay
  12.612 +   between retries (e.g., double the waiting time after each 400
  12.613 +
  12.614 +
  12.615 +
  12.616 +Feather                     Standards Track                    [Page 11]
  12.617 +
  12.618 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.619 +
  12.620 +
  12.621 +   response) or present any associated text to the user for them to
  12.622 +   decide whether and when to retry.
  12.623 +
  12.624 +   The client MUST be prepared to receive any of these responses for any
  12.625 +   command (except, of course, that the server MUST NOT generate a 500
  12.626 +   response code for mandatory commands).
  12.627 +
  12.628 +3.2.1.1.  Examples
  12.629 +
  12.630 +   Example of an unknown command:
  12.631 +
  12.632 +      [C] MAIL
  12.633 +      [S] 500 Unknown command
  12.634 +
  12.635 +   Example of an unsupported command:
  12.636 +
  12.637 +      [C] CAPABILITIES
  12.638 +      [S] 101 Capability list:
  12.639 +      [S] VERSION 2
  12.640 +      [S] READER
  12.641 +      [S] NEWNEWS
  12.642 +      [S] LIST ACTIVE NEWSGROUPS
  12.643 +      [S] .
  12.644 +      [C] OVER
  12.645 +      [S] 500 Unknown command
  12.646 +
  12.647 +   Example of an unsupported variant:
  12.648 +
  12.649 +      [C] MODE POSTER
  12.650 +      [S] 501 Unknown MODE option
  12.651 +
  12.652 +   Example of a syntax error:
  12.653 +
  12.654 +      [C] ARTICLE a.message.id@no.angle.brackets
  12.655 +      [S] 501 Syntax error
  12.656 +
  12.657 +   Example of an overlong command line:
  12.658 +
  12.659 +      [C] HEAD 53 54 55
  12.660 +      [S] 501 Too many arguments
  12.661 +
  12.662 +   Example of a bad wildmat:
  12.663 +
  12.664 +      [C] LIST ACTIVE u[ks].*
  12.665 +      [S] 501 Syntax error
  12.666 +
  12.667 +
  12.668 +
  12.669 +
  12.670 +
  12.671 +
  12.672 +Feather                     Standards Track                    [Page 12]
  12.673 +
  12.674 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.675 +
  12.676 +
  12.677 +   Example of a base64-encoding error (the second argument is meant to
  12.678 +   be base64 encoded):
  12.679 +
  12.680 +      [C] XENCRYPT RSA abcd=efg
  12.681 +      [S] 504 Base64 encoding error
  12.682 +
  12.683 +   Example of an attempt to access a facility not available to this
  12.684 +   connection:
  12.685 +
  12.686 +      [C] MODE READER
  12.687 +      [S] 200 Reader mode, posting permitted
  12.688 +      [C] IHAVE <i.am.an.article.you.will.want@example.com>
  12.689 +      [S] 500 Permission denied
  12.690 +
  12.691 +   Example of an attempt to access a facility requiring authentication:
  12.692 +
  12.693 +      [C] GROUP secret.group
  12.694 +      [S] 480 Permission denied
  12.695 +
  12.696 +   Example of a successful attempt following such authentication:
  12.697 +
  12.698 +      [C] XSECRET fred flintstone
  12.699 +      [S] 290 Password for fred accepted
  12.700 +      [C] GROUP secret.group
  12.701 +      [S] 211 5 1 20 secret.group selected
  12.702 +
  12.703 +   Example of an attempt to access a facility requiring privacy:
  12.704 +
  12.705 +      [C] GROUP secret.group
  12.706 +      [S] 483 Secure connection required
  12.707 +      [C] XENCRYPT
  12.708 +      [Client and server negotiate encryption on the link]
  12.709 +      [S] 283 Encrypted link established
  12.710 +      [C] GROUP secret.group
  12.711 +      [S] 211 5 1 20 secret.group selected
  12.712 +
  12.713 +   Example of a need to change mode before a facility is used:
  12.714 +
  12.715 +      [C] GROUP binary.group
  12.716 +      [S] 401 XHOST Not on this virtual host
  12.717 +      [C] XHOST binary.news.example.org
  12.718 +      [S] 290 binary.news.example.org virtual host selected
  12.719 +      [C] GROUP binary.group
  12.720 +      [S] 211 5 1 77 binary.group selected
  12.721 +
  12.722 +
  12.723 +
  12.724 +
  12.725 +
  12.726 +
  12.727 +
  12.728 +Feather                     Standards Track                    [Page 13]
  12.729 +
  12.730 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.731 +
  12.732 +
  12.733 +   Example of a temporary failure:
  12.734 +
  12.735 +      [C] GROUP archive.local
  12.736 +      [S] 403 Archive server temporarily offline
  12.737 +
  12.738 +   Example of the server needing to close down immediately:
  12.739 +
  12.740 +      [C] ARTICLE 123
  12.741 +      [S] 400 Power supply failed, running on UPS
  12.742 +      [Server closes connection.]
  12.743 +
  12.744 +3.3.  Capabilities and Extensions
  12.745 +
  12.746 +   Not all NNTP servers provide exactly the same facilities, both
  12.747 +   because this specification allows variation and because servers may
  12.748 +   provide extensions.  A set of facilities that are related are called
  12.749 +   a "capability".  This specification provides a way to determine what
  12.750 +   capabilities are available, includes a list of standard capabilities,
  12.751 +   and includes a mechanism (the extension mechanism) for defining new
  12.752 +   capabilities.
  12.753 +
  12.754 +3.3.1.  Capability Descriptions
  12.755 +
  12.756 +   A client can determine the available capabilities of the server by
  12.757 +   using the CAPABILITIES command (Section 5.2).  This returns a
  12.758 +   capability list, which is a list of capability lines.  Each line
  12.759 +   describes one available capability.
  12.760 +
  12.761 +   Each capability line consists of one or more tokens, which MUST be
  12.762 +   separated by one or more space or TAB characters.  A token is a
  12.763 +   string of 1 or more printable UTF-8 characters (that is, either
  12.764 +   printable US-ASCII characters or any UTF-8 sequence outside the US-
  12.765 +   ASCII range, but not space or TAB).  Unless stated otherwise, tokens
  12.766 +   are case insensitive.  Each capability line consists of the
  12.767 +   following:
  12.768 +
  12.769 +   o  The capability label, which is a keyword indicating the
  12.770 +      capability.  A capability label may be defined by this
  12.771 +      specification or a successor, or by an extension.
  12.772 +
  12.773 +   o  The label is then followed by zero or more tokens, which are
  12.774 +      arguments of the capability.  The form and meaning of these tokens
  12.775 +      is specific to each capability.
  12.776 +
  12.777 +   The server MUST ensure that the capability list accurately reflects
  12.778 +   the capabilities (including extensions) currently available.  If a
  12.779 +   capability is only available with the server in a certain state (for
  12.780 +   example, only after authentication), the list MUST only include the
  12.781 +
  12.782 +
  12.783 +
  12.784 +Feather                     Standards Track                    [Page 14]
  12.785 +
  12.786 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.787 +
  12.788 +
  12.789 +   capability label when the server is in that state.  Similarly, if
  12.790 +   only some of the commands in an extension will be available, or if
  12.791 +   the behaviour of the extension will change in some other manner,
  12.792 +   according to the state of the server, this MUST be indicated by
  12.793 +   different arguments in the capability line.
  12.794 +
  12.795 +   Note that a capability line can only begin with a letter.  Lines
  12.796 +   beginning with other characters are reserved for future versions of
  12.797 +   this specification.  In order to interoperate with such versions,
  12.798 +   clients MUST be prepared to receive lines beginning with other
  12.799 +   characters and MUST ignore any they do not understand.
  12.800 +
  12.801 +3.3.2.  Standard Capabilities
  12.802 +
  12.803 +   The following capabilities are defined by this specification.
  12.804 +
  12.805 +   VERSION
  12.806 +      This capability MUST be advertised by all servers and MUST be the
  12.807 +      first capability in the capability list; it indicates the
  12.808 +      version(s) of NNTP that the server supports.  There must be at
  12.809 +      least one argument; each argument is a decimal number and MUST NOT
  12.810 +      have a leading zero.  Version numbers are assigned only in RFCs
  12.811 +      that update or replace this specification; servers MUST NOT create
  12.812 +      their own version numbers.
  12.813 +
  12.814 +      The version number of this specification is 2.
  12.815 +
  12.816 +   READER
  12.817 +      This capability indicates that the server implements the various
  12.818 +      commands useful for reading clients.
  12.819 +
  12.820 +   IHAVE
  12.821 +      This capability indicates that the server implements the IHAVE
  12.822 +      command.
  12.823 +
  12.824 +   POST
  12.825 +      This capability indicates that the server implements the POST
  12.826 +      command.
  12.827 +
  12.828 +   NEWNEWS
  12.829 +      This capability indicates that the server implements the NEWNEWS
  12.830 +      command.
  12.831 +
  12.832 +   HDR
  12.833 +      This capability indicates that the server implements the header
  12.834 +      access commands (HDR and LIST HEADERS).
  12.835 +
  12.836 +
  12.837 +
  12.838 +
  12.839 +
  12.840 +Feather                     Standards Track                    [Page 15]
  12.841 +
  12.842 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.843 +
  12.844 +
  12.845 +   OVER
  12.846 +      This capability indicates that the server implements the overview
  12.847 +      access commands (OVER and LIST OVERVIEW.FMT).  If and only if the
  12.848 +      server supports the message-id form of the OVER command, there
  12.849 +      must be a single argument MSGID.
  12.850 +
  12.851 +   LIST
  12.852 +      This capability indicates that the server implements at least one
  12.853 +      variant of the LIST command.  There MUST be one argument for each
  12.854 +      variant of the LIST command supported by the server, giving the
  12.855 +      keyword for that variant.
  12.856 +
  12.857 +   IMPLEMENTATION
  12.858 +      This capability MAY be provided by a server.  If so, the arguments
  12.859 +      SHOULD be used to provide information such as the server software
  12.860 +      name and version number.  The client MUST NOT use this line to
  12.861 +      determine capabilities of the server.  (While servers often
  12.862 +      provide this information in the initial greeting, clients need to
  12.863 +      guess whether this is the case; this capability makes it clear
  12.864 +      what the information is.)
  12.865 +
  12.866 +   MODE-READER
  12.867 +      This capability indicates that the server is mode-switching
  12.868 +      (Section 3.4.2) and that the MODE READER command needs to be used
  12.869 +      to enable the READER capability.
  12.870 +
  12.871 +3.3.3.  Extensions
  12.872 +
  12.873 +   Although NNTP is widely and robustly deployed, some parts of the
  12.874 +   Internet community might wish to extend the NNTP service.  It must be
  12.875 +   emphasized that any extension to NNTP should not be considered
  12.876 +   lightly.  NNTP's strength comes primarily from its simplicity.
  12.877 +   Experience with many protocols has shown that:
  12.878 +
  12.879 +      Protocols with few options tend towards ubiquity, whilst protocols
  12.880 +      with many options tend towards obscurity.
  12.881 +
  12.882 +   This means that each and every extension, regardless of its benefits,
  12.883 +   must be carefully scrutinized with respect to its implementation,
  12.884 +   deployment, and interoperability costs.  In many cases, the cost of
  12.885 +   extending the NNTP service will likely outweigh the benefit.
  12.886 +
  12.887 +   An extension is a package of associated facilities, often but not
  12.888 +   always including one or more new commands.  Each extension MUST
  12.889 +   define at least one new capability label (this will often, but need
  12.890 +   not, be the name of one of these new commands).  While any additional
  12.891 +   capability information can normally be specified using arguments to
  12.892 +
  12.893 +
  12.894 +
  12.895 +
  12.896 +Feather                     Standards Track                    [Page 16]
  12.897 +
  12.898 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.899 +
  12.900 +
  12.901 +   that label, an extension MAY define more than one capability label.
  12.902 +   However, this SHOULD be limited to exceptional circumstances.
  12.903 +
  12.904 +   An extension is either a private extension, or its capabilities are
  12.905 +   included in the IANA registry of capabilities (see Section 3.3.4) and
  12.906 +   it is defined in an RFC (in which case it is a "registered
  12.907 +   extension").  Such RFCs either must be on the standards track or must
  12.908 +   define an IESG-approved experimental protocol.
  12.909 +
  12.910 +   The definition of an extension must include the following:
  12.911 +
  12.912 +   o  a descriptive name for the extension.
  12.913 +
  12.914 +   o  the capability label or labels defined by the extension (the
  12.915 +      capability label of a registered extension MUST NOT begin with
  12.916 +      "X").
  12.917 +
  12.918 +   o  The syntax, values, and meanings of any arguments for each
  12.919 +      capability label defined by the extension.
  12.920 +
  12.921 +   o  Any new NNTP commands associated with the extension (the names of
  12.922 +      commands associated with registered extensions MUST NOT begin with
  12.923 +      "X").
  12.924 +
  12.925 +   o  The syntax and possible values of arguments associated with the
  12.926 +      new NNTP commands.
  12.927 +
  12.928 +   o  The response codes and possible values of arguments for the
  12.929 +      responses of the new NNTP commands.
  12.930 +
  12.931 +   o  Any new arguments the extension associates with any other
  12.932 +      pre-existing NNTP commands.
  12.933 +
  12.934 +   o  Any increase in the maximum length of commands and initial
  12.935 +      response lines over the value specified in this document.
  12.936 +
  12.937 +   o  A specific statement about the effect on pipelining that this
  12.938 +      extension may have (if any).
  12.939 +
  12.940 +   o  A specific statement about the circumstances when use of this
  12.941 +      extension can alter the contents of the capabilities list (other
  12.942 +      than the new capability labels it defines).
  12.943 +
  12.944 +   o  A specific statement about the circumstances under which the
  12.945 +      extension can cause any pre-existing command to produce a 401,
  12.946 +      480, or 483 response.
  12.947 +
  12.948 +
  12.949 +
  12.950 +
  12.951 +
  12.952 +Feather                     Standards Track                    [Page 17]
  12.953 +
  12.954 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  12.955 +
  12.956 +
  12.957 +   o  A description of how the use of MODE READER on a mode-switching
  12.958 +      server interacts with the extension.
  12.959 +
  12.960 +   o  A description of how support for the extension affects the
  12.961 +      behaviour of a server and NNTP client in any other manner not
  12.962 +      outlined above.
  12.963 +
  12.964 +   o  Formal syntax as described in Section 9.9.
  12.965 +
  12.966 +   A private extension MAY or MAY NOT be included in the capabilities
  12.967 +   list.  If it is, the capability label MUST begin with "X".  A server
  12.968 +   MAY provide additional keywords (for new commands and also for new
  12.969 +   variants of existing commands) as part of a private extension.  To
  12.970 +   avoid the risk of a clash with a future registered extension, these
  12.971 +   keywords SHOULD begin with "X".
  12.972 +
  12.973 +   If the server advertises a capability defined by a registered
  12.974 +   extension, it MUST implement the extension so as to fully conform
  12.975 +   with the specification (for example, it MUST implement all the
  12.976 +   commands that the extension describes as mandatory).  If it does not
  12.977 +   implement the extension as specified, it MUST NOT list the extension
  12.978 +   in the capabilities list under its registered name.  In that case, it
  12.979 +   MAY, but SHOULD NOT, provide a private extension (not listed, or
  12.980 +   listed with a different name) that implements part of the extension
  12.981 +   or implements the commands of the extension with a different meaning.
  12.982 +
  12.983 +   A server MUST NOT send different response codes to basic NNTP
  12.984 +   commands documented here or to commands documented in registered
  12.985 +   extensions in response to the availability or use of a private
  12.986 +   extension.
  12.987 +
  12.988 +3.3.4.  Initial IANA Register
  12.989 +
  12.990 +   IANA will maintain a registry of NNTP capability labels.  All
  12.991 +   capability labels in the registry MUST be keywords and MUST NOT begin
  12.992 +   with X.
  12.993 +
  12.994 +
  12.995 +
  12.996 +
  12.997 +
  12.998 +
  12.999 +
 12.1000 +
 12.1001 +
 12.1002 +
 12.1003 +
 12.1004 +
 12.1005 +
 12.1006 +
 12.1007 +
 12.1008 +Feather                     Standards Track                    [Page 18]
 12.1009 +
 12.1010 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1011 +
 12.1012 +
 12.1013 +   The initial content of the registry consists of these entries:
 12.1014 +
 12.1015 +   +-------------------+--------------------------+--------------------+
 12.1016 +   | Label             | Meaning                  | Definition         |
 12.1017 +   +-------------------+--------------------------+--------------------+
 12.1018 +   | AUTHINFO          | Authentication           | [NNTP-AUTH]        |
 12.1019 +   |                   |                          |                    |
 12.1020 +   | HDR               | Batched header retrieval | Section 3.3.2,     |
 12.1021 +   |                   |                          | Section 8.5, and   |
 12.1022 +   |                   |                          | Section 8.6        |
 12.1023 +   |                   |                          |                    |
 12.1024 +   | IHAVE             | IHAVE command available  | Section 3.3.2 and  |
 12.1025 +   |                   |                          | Section 6.3.2      |
 12.1026 +   |                   |                          |                    |
 12.1027 +   | IMPLEMENTATION    | Server                   | Section 3.3.2      |
 12.1028 +   |                   | implementation-specific  |                    |
 12.1029 +   |                   | information              |                    |
 12.1030 +   |                   |                          |                    |
 12.1031 +   | LIST              | LIST command variants    | Section 3.3.2 and  |
 12.1032 +   |                   |                          | Section 7.6.1      |
 12.1033 +   |                   |                          |                    |
 12.1034 +   | MODE-READER       | Mode-switching server    | Section 3.4.2      |
 12.1035 +   |                   | and MODE READER command  |                    |
 12.1036 +   |                   | available                |                    |
 12.1037 +   |                   |                          |                    |
 12.1038 +   | NEWNEWS           | NEWNEWS command          | Section 3.3.2 and  |
 12.1039 +   |                   | available                | Section 7.4        |
 12.1040 +   |                   |                          |                    |
 12.1041 +   | OVER              | Overview support         | Section 3.3.2,     |
 12.1042 +   |                   |                          | Section 8.3, and   |
 12.1043 +   |                   |                          | Section 8.4        |
 12.1044 +   |                   |                          |                    |
 12.1045 +   | POST              | POST command available   | Section 3.3.2 and  |
 12.1046 +   |                   |                          | Section 6.3.1      |
 12.1047 +   |                   |                          |                    |
 12.1048 +   | READER            | Reader commands          | Section 3.3.2      |
 12.1049 +   |                   | available                |                    |
 12.1050 +   |                   |                          |                    |
 12.1051 +   | SASL              | Supported SASL           | [NNTP-AUTH]        |
 12.1052 +   |                   | mechanisms               |                    |
 12.1053 +   |                   |                          |                    |
 12.1054 +   | STARTTLS          | Transport layer security | [NNTP-TLS]         |
 12.1055 +   |                   |                          |                    |
 12.1056 +   | STREAMING         | Streaming feeds          | [NNTP-STREAM]      |
 12.1057 +   |                   |                          |                    |
 12.1058 +   | VERSION           | Supported NNTP versions  | Section 3.3.2      |
 12.1059 +   +-------------------+--------------------------+--------------------+
 12.1060 +
 12.1061 +
 12.1062 +
 12.1063 +
 12.1064 +Feather                     Standards Track                    [Page 19]
 12.1065 +
 12.1066 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1067 +
 12.1068 +
 12.1069 +3.4.  Mandatory and Optional Commands
 12.1070 +
 12.1071 +   For a number of reasons, not all the commands in this specification
 12.1072 +   are mandatory.  However, it is equally undesirable for every command
 12.1073 +   to be optional, since this means that a client will have no idea what
 12.1074 +   facilities are available.  Therefore, as a compromise, some of the
 12.1075 +   commands in this specification are mandatory (they must be supported
 12.1076 +   by all servers) while the remainder are not.  The latter are then
 12.1077 +   subdivided into bundles, each indicated by a single capability label.
 12.1078 +
 12.1079 +   o  If the label is included in the capability list returned by the
 12.1080 +      server, the server MUST support all commands in that bundle.
 12.1081 +
 12.1082 +   o  If the label is not included, the server MAY support none or some
 12.1083 +      of the commands but SHOULD NOT support all of them.  In general,
 12.1084 +      there will be no way for a client to determine which commands are
 12.1085 +      supported without trying them.
 12.1086 +
 12.1087 +   The bundles have been chosen to provide useful functionality, and
 12.1088 +   therefore server authors are discouraged from implementing only part
 12.1089 +   of a bundle.
 12.1090 +
 12.1091 +   The description of each command will either indicate that it is
 12.1092 +   mandatory, or will give, using the term "indicating capability", the
 12.1093 +   capability label indicating whether the bundle including this command
 12.1094 +   is available.
 12.1095 +
 12.1096 +   Where a server does not implement a command, it MUST always generate
 12.1097 +   a 500 generic response code (or a 501 generic response code in the
 12.1098 +   case of a variant of a command depending on a second keyword where
 12.1099 +   the base command is recognised).  Otherwise, the command MUST be
 12.1100 +   fully implemented as specified; a server MUST NOT only partially
 12.1101 +   implement any of the commands in this specification.  (Client authors
 12.1102 +   should note that some servers not conforming to this specification
 12.1103 +   will return a 502 generic response code to some commands that are not
 12.1104 +   implemented.)
 12.1105 +
 12.1106 +   Note: some commands have cases that require other commands to be used
 12.1107 +   first.  If the former command is implemented but the latter is not,
 12.1108 +   the former MUST still generate the relevant specific response code.
 12.1109 +   For example, if ARTICLE (Section 6.2.1) is implemented but GROUP
 12.1110 +   (Section 6.1.1) is not, the correct response to "ARTICLE 1234"
 12.1111 +   remains 412.
 12.1112 +
 12.1113 +
 12.1114 +
 12.1115 +
 12.1116 +
 12.1117 +
 12.1118 +
 12.1119 +
 12.1120 +Feather                     Standards Track                    [Page 20]
 12.1121 +
 12.1122 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1123 +
 12.1124 +
 12.1125 +3.4.1.  Reading and Transit Servers
 12.1126 +
 12.1127 +   NNTP is traditionally used in two different ways.  The first use is
 12.1128 +   "reading", where the client fetches articles from a large store
 12.1129 +   maintained by the server for immediate or later presentation to a
 12.1130 +   user and sends articles created by that user back to the server (an
 12.1131 +   action called "posting") to be stored and distributed to other stores
 12.1132 +   and users.  The second use is for the bulk transfer of articles from
 12.1133 +   one store to another.  Since the hosts making this transfer tend to
 12.1134 +   be peers in a network that transmit articles among one another, and
 12.1135 +   not end-user systems, this process is called "peering" or "transit".
 12.1136 +   (Even so, one host is still the client and the other is the server).
 12.1137 +
 12.1138 +   In practice, these two uses are so different that some server
 12.1139 +   implementations are optimised for reading or for transit and, as a
 12.1140 +   result, do not offer the other facility or only offer limited
 12.1141 +   features.  Other implementations are more general and offer both.
 12.1142 +   This specification allows for this by bundling the relevant commands
 12.1143 +   accordingly: the IHAVE command is designed for transit, while the
 12.1144 +   commands indicated by the READER capability are designed for reading
 12.1145 +   clients.
 12.1146 +
 12.1147 +   Except as an effect of the MODE READER command (Section 5.3) on a
 12.1148 +   mode-switching server, once a server advertises either or both of the
 12.1149 +   IHAVE or READER capabilities, it MUST continue to advertise them for
 12.1150 +   the entire session.
 12.1151 +
 12.1152 +   A server MAY provide different modes of behaviour (transit, reader,
 12.1153 +   or a combination) to different client connections and MAY use
 12.1154 +   external information, such as the IP address of the client, to
 12.1155 +   determine which mode to provide to any given connection.
 12.1156 +
 12.1157 +   The official TCP port for the NNTP service is 119.  However, if a
 12.1158 +   host wishes to offer separate servers for transit and reading
 12.1159 +   clients, port 433 SHOULD be used for the transit server and 119 for
 12.1160 +   the reading server.
 12.1161 +
 12.1162 +3.4.2.  Mode Switching
 12.1163 +
 12.1164 +   An implementation MAY, but SHOULD NOT, provide both transit and
 12.1165 +   reader facilities on the same server but require the client to select
 12.1166 +   which it wishes to use.  Such an arrangement is called a
 12.1167 +   "mode-switching" server.
 12.1168 +
 12.1169 +
 12.1170 +
 12.1171 +
 12.1172 +
 12.1173 +
 12.1174 +
 12.1175 +
 12.1176 +Feather                     Standards Track                    [Page 21]
 12.1177 +
 12.1178 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1179 +
 12.1180 +
 12.1181 +   A mode-switching server has two modes:
 12.1182 +
 12.1183 +   o  Transit mode, which applies after the initial connection.
 12.1184 +
 12.1185 +      *  It MUST advertise the MODE-READER capability.
 12.1186 +
 12.1187 +      *  It MUST NOT advertise the READER capability.
 12.1188 +
 12.1189 +      However, the server MAY cease to advertise the MODE-READER
 12.1190 +      capability after the client uses any command except CAPABILITIES.
 12.1191 +
 12.1192 +   o  Reading mode, after a successful MODE READER command (see Section
 12.1193 +      5.3).
 12.1194 +
 12.1195 +      *  It MUST NOT advertise the MODE-READER capability.
 12.1196 +
 12.1197 +      *  It MUST advertise the READER capability.
 12.1198 +
 12.1199 +      *  It MAY NOT advertise the IHAVE capability, even if it was
 12.1200 +         advertising it in transit mode.
 12.1201 +
 12.1202 +   A client SHOULD only issue a MODE READER command to a server if it is
 12.1203 +   advertising the MODE-READER capability.  If the server does not
 12.1204 +   support CAPABILITIES (and therefore does not conform to this
 12.1205 +   specification), the client MAY use the following heuristic:
 12.1206 +
 12.1207 +   o  If the client wishes to use any "reader" commands, it SHOULD use
 12.1208 +      the MODE READER command immediately after the initial connection.
 12.1209 +
 12.1210 +   o  Otherwise, it SHOULD NOT use the MODE READER command.
 12.1211 +
 12.1212 +   In each case, it should be prepared for some commands to be
 12.1213 +   unavailable that would have been available if it had made the other
 12.1214 +   choice.
 12.1215 +
 12.1216 +3.5.  Pipelining
 12.1217 +
 12.1218 +   NNTP is designed to operate over a reliable bi-directional
 12.1219 +   connection, such as TCP.  Therefore, if a command does not depend on
 12.1220 +   the response to the previous one, it should not matter if it is sent
 12.1221 +   before that response is received.  Doing this is called "pipelining".
 12.1222 +   However, certain server implementations throw away all text received
 12.1223 +   from the client following certain commands before sending their
 12.1224 +   response.  If this happens, pipelining will be affected because one
 12.1225 +   or more commands will have been ignored or misinterpreted, and the
 12.1226 +   client will be matching the wrong responses to each command.  Since
 12.1227 +   there are significant benefits to pipelining, but also circumstances
 12.1228 +   where it is reasonable or common for servers to behave in the above
 12.1229 +
 12.1230 +
 12.1231 +
 12.1232 +Feather                     Standards Track                    [Page 22]
 12.1233 +
 12.1234 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1235 +
 12.1236 +
 12.1237 +   manner, this document puts certain requirements on both clients and
 12.1238 +   servers.
 12.1239 +
 12.1240 +   Except where stated otherwise, a client MAY use pipelining.  That is,
 12.1241 +   it may send a command before receiving the response for the previous
 12.1242 +   command.  The server MUST allow pipelining and MUST NOT throw away
 12.1243 +   any text received after a command.  Irrespective of whether
 12.1244 +   pipelining is used, the server MUST process commands in the order
 12.1245 +   they are sent.
 12.1246 +
 12.1247 +   If the specific description of a command says it "MUST NOT be
 12.1248 +   pipelined", that command MUST end any pipeline of commands.  That is,
 12.1249 +   the client MUST NOT send any following command until it receives the
 12.1250 +   CRLF at the end of the response from the command.  The server MAY
 12.1251 +   ignore any data received after the command and before the CRLF at the
 12.1252 +   end of the response is sent to the client.
 12.1253 +
 12.1254 +   The initial connection must not be part of a pipeline; that is, the
 12.1255 +   client MUST NOT send any command until it receives the CRLF at the
 12.1256 +   end of the greeting.
 12.1257 +
 12.1258 +   If the client uses blocking system calls to send commands, it MUST
 12.1259 +   ensure that the amount of text sent in pipelining does not cause a
 12.1260 +   deadlock between transmission and reception.  The amount of text
 12.1261 +   involved will depend on window sizes in the transmission layer;
 12.1262 +   typically, it is 4k octets for TCP.  (Since the server only sends
 12.1263 +   data in response to commands from the client, the converse problem
 12.1264 +   does not occur.)
 12.1265 +
 12.1266 +3.5.1.  Examples
 12.1267 +
 12.1268 +   Example of correct use of pipelining:
 12.1269 +
 12.1270 +      [C] GROUP misc.test
 12.1271 +      [C] STAT
 12.1272 +      [C] NEXT
 12.1273 +      [S] 211 1234 3000234 3002322 misc.test
 12.1274 +      [S] 223 3000234 <45223423@example.com> retrieved
 12.1275 +      [S] 223 3000237 <668929@example.org> retrieved
 12.1276 +
 12.1277 +   Example of incorrect use of pipelining (the MODE READER command may
 12.1278 +   not be pipelined):
 12.1279 +
 12.1280 +      [C] MODE READER
 12.1281 +      [C] DATE
 12.1282 +      [C] NEXT
 12.1283 +      [S] 200 Server ready, posting allowed
 12.1284 +      [S] 223 3000237 <668929@example.org> retrieved
 12.1285 +
 12.1286 +
 12.1287 +
 12.1288 +Feather                     Standards Track                    [Page 23]
 12.1289 +
 12.1290 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1291 +
 12.1292 +
 12.1293 +   The DATE command has been thrown away by the server, so there is no
 12.1294 +   111 response to match it.
 12.1295 +
 12.1296 +3.6.  Articles
 12.1297 +
 12.1298 +   NNTP is intended to transfer articles between clients and servers.
 12.1299 +   For the purposes of this specification, articles are required to
 12.1300 +   conform to the rules in this section, and clients and servers MUST
 12.1301 +   correctly process any article received from the other that does so.
 12.1302 +   Note that this requirement applies only to the contents of
 12.1303 +   communications over NNTP; it does not prevent the client or server
 12.1304 +   from subsequently rejecting an article for reasons of local policy.
 12.1305 +   Also see Appendix A for further restrictions on the format of
 12.1306 +   articles in some uses of NNTP.
 12.1307 +
 12.1308 +   An article consists of two parts: the headers and the body.  They are
 12.1309 +   separated by a single empty line, or in other words by two
 12.1310 +   consecutive CRLF pairs (if there is more than one empty line, the
 12.1311 +   second and subsequent ones are part of the body).  In order to meet
 12.1312 +   the general requirements of NNTP, an article MUST NOT include the
 12.1313 +   octet NUL, MUST NOT contain the octets LF and CR other than as part
 12.1314 +   of a CRLF pair, and MUST end with a CRLF pair.  This specification
 12.1315 +   puts no further restrictions on the body; in particular, it MAY be
 12.1316 +   empty.
 12.1317 +
 12.1318 +   The headers of an article consist of one or more header lines.  Each
 12.1319 +   header line consists of a header name, a colon, a space, the header
 12.1320 +   content, and a CRLF, in that order.  The name consists of one or more
 12.1321 +   printable US-ASCII characters other than colon and, for the purposes
 12.1322 +   of this specification, is not case sensitive.  There MAY be more than
 12.1323 +   one header line with the same name.  The content MUST NOT contain
 12.1324 +   CRLF; it MAY be empty.  A header may be "folded"; that is, a CRLF
 12.1325 +   pair may be placed before any TAB or space in the line.  There MUST
 12.1326 +   still be some other octet between any two CRLF pairs in a header
 12.1327 +   line.  (Note that folding means that the header line occupies more
 12.1328 +   than one line when displayed or transmitted; nevertheless, it is
 12.1329 +   still referred to as "a" header line.)  The presence or absence of
 12.1330 +   folding does not affect the meaning of the header line; that is, the
 12.1331 +   CRLF pairs introduced by folding are not considered part of the
 12.1332 +   header content.  Header lines SHOULD NOT be folded before the space
 12.1333 +   after the colon that follows the header name and SHOULD include at
 12.1334 +   least one octet other than %x09 or %x20 between CRLF pairs.  However,
 12.1335 +   if an article that fails to satisfy this requirement has been
 12.1336 +   received from elsewhere, clients and servers MAY transfer it to each
 12.1337 +   other without re-folding it.
 12.1338 +
 12.1339 +
 12.1340 +
 12.1341 +
 12.1342 +
 12.1343 +
 12.1344 +Feather                     Standards Track                    [Page 24]
 12.1345 +
 12.1346 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1347 +
 12.1348 +
 12.1349 +   The content of a header SHOULD be in UTF-8.  However, if an
 12.1350 +   implementation receives an article from elsewhere that uses octets in
 12.1351 +   the range 128 to 255 in some other manner, it MAY pass it to a client
 12.1352 +   or server without modification.  Therefore, implementations MUST be
 12.1353 +   prepared to receive such headers, and data derived from them (e.g.,
 12.1354 +   in the responses from the OVER command, Section 8.3), and MUST NOT
 12.1355 +   assume that they are always UTF-8.  Any external processing of those
 12.1356 +   headers, including identifying the encoding used, is outside the
 12.1357 +   scope of this document.
 12.1358 +
 12.1359 +   Each article MUST have a unique message-id; two articles offered by
 12.1360 +   an NNTP server MUST NOT have the same message-id.  For the purposes
 12.1361 +   of this specification, message-ids are opaque strings that MUST meet
 12.1362 +   the following requirements:
 12.1363 +
 12.1364 +   o  A message-id MUST begin with "<", end with ">", and MUST NOT
 12.1365 +      contain the latter except at the end.
 12.1366 +
 12.1367 +   o  A message-id MUST be between 3 and 250 octets in length.
 12.1368 +
 12.1369 +   o  A message-id MUST NOT contain octets other than printable US-ASCII
 12.1370 +      characters.
 12.1371 +
 12.1372 +   Two message-ids are the same if and only if they consist of the same
 12.1373 +   sequence of octets.
 12.1374 +
 12.1375 +   This specification does not describe how the message-id of an article
 12.1376 +   is determined.  If the server does not have any way to determine a
 12.1377 +   message-id from the article itself, it MUST synthesize one (this
 12.1378 +   specification does not require that the article be changed as a
 12.1379 +   result).  See also Appendix A.2.
 12.1380 +
 12.1381 +4.  The WILDMAT Format
 12.1382 +
 12.1383 +   The WILDMAT format described here is based on the version first
 12.1384 +   developed by Rich Salz [SALZ1992], which was in turn derived from the
 12.1385 +   format used in the UNIX "find" command to articulate file names.  It
 12.1386 +   was developed to provide a uniform mechanism for matching patterns in
 12.1387 +   the same manner that the UNIX shell matches filenames.
 12.1388 +
 12.1389 +
 12.1390 +
 12.1391 +
 12.1392 +
 12.1393 +
 12.1394 +
 12.1395 +
 12.1396 +
 12.1397 +
 12.1398 +
 12.1399 +
 12.1400 +Feather                     Standards Track                    [Page 25]
 12.1401 +
 12.1402 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1403 +
 12.1404 +
 12.1405 +4.1.  Wildmat Syntax
 12.1406 +
 12.1407 +   A wildmat is described by the following ABNF [RFC4234] syntax, which
 12.1408 +   is an extract of that in Section 9.8.
 12.1409 +
 12.1410 +     wildmat = wildmat-pattern *("," ["!"] wildmat-pattern)
 12.1411 +     wildmat-pattern = 1*wildmat-item
 12.1412 +     wildmat-item = wildmat-exact / wildmat-wild
 12.1413 +     wildmat-exact = %x22-29 / %x2B / %x2D-3E / %x40-5A / %x5E-7E /
 12.1414 +          UTF8-non-ascii ; exclude ! * , ? [ \ ]
 12.1415 +     wildmat-wild = "*" / "?"
 12.1416 +
 12.1417 +   Note: the characters ",", "\", "[", and "]" are not allowed in
 12.1418 +   wildmats, while * and ? are always wildcards.  This should not be a
 12.1419 +   problem, since these characters cannot occur in newsgroup names,
 12.1420 +   which is the only current use of wildmats.  Backslash is commonly
 12.1421 +   used to suppress the special meaning of characters, whereas brackets
 12.1422 +   are used to introduce sets.  However, these usages are not universal,
 12.1423 +   and interpretation of these characters in the context of UTF-8
 12.1424 +   strings is potentially complex and differs from existing practice, so
 12.1425 +   they were omitted from this specification.  A future extension to
 12.1426 +   this specification may provide semantics for these characters.
 12.1427 +
 12.1428 +4.2.  Wildmat Semantics
 12.1429 +
 12.1430 +   A wildmat is tested against a string and either matches or does not
 12.1431 +   match.  To do this, each constituent <wildmat-pattern> is matched
 12.1432 +   against the string, and the rightmost pattern that matches is
 12.1433 +   identified.  If that <wildmat-pattern> is not preceded with "!", the
 12.1434 +   whole wildmat matches.  If it is preceded by "!", or if no <wildmat-
 12.1435 +   pattern> matches, the whole wildmat does not match.
 12.1436 +
 12.1437 +   For example, consider the wildmat "a*,!*b,*c*":
 12.1438 +
 12.1439 +   o  The string "aaa" matches because the rightmost match is with "a*".
 12.1440 +
 12.1441 +   o  The string "abb" does not match because the rightmost match is
 12.1442 +      with "*b".
 12.1443 +
 12.1444 +   o  The string "ccb" matches because the rightmost match is with
 12.1445 +      "*c*".
 12.1446 +
 12.1447 +   o  The string "xxx" does not match because no <wildmat-pattern>
 12.1448 +      matches.
 12.1449 +
 12.1450 +   A <wildmat-pattern> matches a string if the string can be broken into
 12.1451 +   components, each of which matches the corresponding <wildmat-item> in
 12.1452 +   the pattern.  The matches must be in the same order, and the whole
 12.1453 +
 12.1454 +
 12.1455 +
 12.1456 +Feather                     Standards Track                    [Page 26]
 12.1457 +
 12.1458 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1459 +
 12.1460 +
 12.1461 +   string must be used in the match.  The pattern is "anchored"; that
 12.1462 +   is, the first and last characters in the string must match the first
 12.1463 +   and last item, respectively (unless that item is an asterisk matching
 12.1464 +   zero characters).
 12.1465 +
 12.1466 +   A <wildmat-exact> matches the same character (which may be more than
 12.1467 +   one octet in UTF-8).
 12.1468 +
 12.1469 +   "?" matches exactly one character (which may be more than one octet).
 12.1470 +
 12.1471 +   "*" matches zero or more characters.  It can match an empty string,
 12.1472 +   but it cannot match a subsequence of a UTF-8 sequence that is not
 12.1473 +   aligned to the character boundaries.
 12.1474 +
 12.1475 +4.3.  Extensions
 12.1476 +
 12.1477 +   An NNTP server or extension MAY extend the syntax or semantics of
 12.1478 +   wildmats provided that all wildmats that meet the requirements of
 12.1479 +   Section 4.1 have the meaning ascribed to them by Section 4.2.  Future
 12.1480 +   editions of this document may also extend wildmats.
 12.1481 +
 12.1482 +4.4.  Examples
 12.1483 +
 12.1484 +   In these examples, $ and @ are used to represent the two octets %xC2
 12.1485 +   and %xA3, respectively; $@ is thus the UTF-8 encoding for the pound
 12.1486 +   sterling symbol, shown as # in the descriptions.
 12.1487 +
 12.1488 +     Wildmat    Description of strings that match
 12.1489 +       abc      The one string "abc"
 12.1490 +       abc,def  The two strings "abc" and "def"
 12.1491 +       $@       The one character string "#"
 12.1492 +       a*       Any string that begins with "a"
 12.1493 +       a*b      Any string that begins with "a" and ends with "b"
 12.1494 +       a*,*b    Any string that begins with "a" or ends with "b"
 12.1495 +       a*,!*b   Any string that begins with "a" and does not end with
 12.1496 +                "b"
 12.1497 +     a*,!*b,c*  Any string that begins with "a" and does not end with
 12.1498 +                "b", and any string that begins with "c" no matter
 12.1499 +                what it ends with
 12.1500 +     a*,c*,!*b  Any string that begins with "a" or "c" and does not
 12.1501 +                end with "b"
 12.1502 +       ?a*      Any string with "a" as its second character
 12.1503 +       ??a*     Any string with "a" as its third character
 12.1504 +       *a?      Any string with "a" as its penultimate character
 12.1505 +       *a??     Any string with "a" as its antepenultimate character
 12.1506 +
 12.1507 +
 12.1508 +
 12.1509 +
 12.1510 +
 12.1511 +
 12.1512 +Feather                     Standards Track                    [Page 27]
 12.1513 +
 12.1514 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1515 +
 12.1516 +
 12.1517 +5.  Session Administration Commands
 12.1518 +
 12.1519 +5.1.  Initial Connection
 12.1520 +
 12.1521 +5.1.1.  Usage
 12.1522 +
 12.1523 +   This command MUST NOT be pipelined.
 12.1524 +
 12.1525 +   Responses [1]
 12.1526 +     200    Service available, posting allowed
 12.1527 +     201    Service available, posting prohibited
 12.1528 +     400    Service temporarily unavailable [2]
 12.1529 +     502    Service permanently unavailable [2]
 12.1530 +
 12.1531 +   [1] These are the only valid response codes for the initial greeting;
 12.1532 +       the server MUST not return any other generic response code.
 12.1533 +
 12.1534 +   [2] Following a 400 or 502 response, the server MUST immediately
 12.1535 +       close the connection.
 12.1536 +
 12.1537 +5.1.2.  Description
 12.1538 +
 12.1539 +   There is no command presented by the client upon initial connection
 12.1540 +   to the server.  The server MUST present an appropriate response code
 12.1541 +   as a greeting to the client.  This response informs the client
 12.1542 +   whether service is available and whether the client is permitted to
 12.1543 +   post.
 12.1544 +
 12.1545 +   If the server will accept further commands from the client including
 12.1546 +   POST, the server MUST present a 200 greeting code.  If the server
 12.1547 +   will accept further commands from the client, but the client is not
 12.1548 +   authorized to post articles using the POST command, the server MUST
 12.1549 +   present a 201 greeting code.
 12.1550 +
 12.1551 +   Otherwise, the server MUST present a 400 or 502 greeting code and
 12.1552 +   then immediately close the connection. 400 SHOULD be used if the
 12.1553 +   issue is only temporary (for example, because of load) and the client
 12.1554 +   can expect to be able to connect successfully at some point in the
 12.1555 +   future without making any changes. 502 MUST be used if the client is
 12.1556 +   not permitted under any circumstances to interact with the server,
 12.1557 +   and MAY be used if the server has insufficient information to
 12.1558 +   determine whether the issue is temporary or permanent.
 12.1559 +
 12.1560 +   Note: the distinction between the 200 and 201 response codes has
 12.1561 +   turned out in practice to be insufficient; for example, some servers
 12.1562 +   do not allow posting until the client has authenticated, while other
 12.1563 +   clients assume that a 201 response means that posting will never be
 12.1564 +   possible even after authentication.  Therefore, clients SHOULD use
 12.1565 +
 12.1566 +
 12.1567 +
 12.1568 +Feather                     Standards Track                    [Page 28]
 12.1569 +
 12.1570 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1571 +
 12.1572 +
 12.1573 +   the CAPABILITIES command (Section 5.2) rather than rely on this
 12.1574 +   response.
 12.1575 +
 12.1576 +5.1.3.  Examples
 12.1577 +
 12.1578 +   Example of a normal connection from an authorized client that then
 12.1579 +   terminates the session (see Section 5.4):
 12.1580 +
 12.1581 +      [Initial connection set-up completed.]
 12.1582 +      [S] 200 NNTP Service Ready, posting permitted
 12.1583 +      [C] QUIT
 12.1584 +      [S] 205 NNTP Service exits normally
 12.1585 +      [Server closes connection.]
 12.1586 +
 12.1587 +   Example of a normal connection from an authorized client that is not
 12.1588 +   permitted to post, which also immediately terminates the session:
 12.1589 +
 12.1590 +      [Initial connection set-up completed.]
 12.1591 +      [S] 201 NNTP Service Ready, posting prohibited
 12.1592 +      [C] QUIT
 12.1593 +      [S] 205 NNTP Service exits normally
 12.1594 +      [Server closes connection.]
 12.1595 +
 12.1596 +   Example of a normal connection from an unauthorized client:
 12.1597 +
 12.1598 +      [Initial connection set-up completed.]
 12.1599 +      [S] 502 NNTP Service permanently unavailable
 12.1600 +      [Server closes connection.]
 12.1601 +
 12.1602 +   Example of a connection from a client if the server is unable to
 12.1603 +   provide service:
 12.1604 +
 12.1605 +      [Initial connection set-up completed.]
 12.1606 +      [S] 400 NNTP Service temporarily unavailable
 12.1607 +      [Server closes connection.]
 12.1608 +
 12.1609 +5.2.  CAPABILITIES
 12.1610 +
 12.1611 +5.2.1.  Usage
 12.1612 +
 12.1613 +   This command is mandatory.
 12.1614 +
 12.1615 +   Syntax
 12.1616 +     CAPABILITIES [keyword]
 12.1617 +
 12.1618 +   Responses
 12.1619 +     101    Capability list follows (multi-line)
 12.1620 +
 12.1621 +
 12.1622 +
 12.1623 +
 12.1624 +Feather                     Standards Track                    [Page 29]
 12.1625 +
 12.1626 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1627 +
 12.1628 +
 12.1629 +   Parameters
 12.1630 +     keyword    additional feature, see description
 12.1631 +
 12.1632 +5.2.2.  Description
 12.1633 +
 12.1634 +   The CAPABILITIES command allows a client to determine the
 12.1635 +   capabilities of the server at any given time.
 12.1636 +
 12.1637 +   This command MAY be issued at any time; the server MUST NOT require
 12.1638 +   it to be issued in order to make use of any capability.  The response
 12.1639 +   generated by this command MAY change during a session because of
 12.1640 +   other state information (which, in turn, may be changed by the
 12.1641 +   effects of other commands or by external events).  An NNTP client is
 12.1642 +   only able to get the current and correct information concerning
 12.1643 +   available capabilities at any point during a session by issuing a
 12.1644 +   CAPABILITIES command at that point of that session and processing the
 12.1645 +   response.
 12.1646 +
 12.1647 +   The capability list is returned as a multi-line data block following
 12.1648 +   the 101 response code.  Each capability is described by a separate
 12.1649 +   capability line.  The server MUST NOT list the same capability twice
 12.1650 +   in the response, even with different arguments.  Except that the
 12.1651 +   VERSION capability MUST be the first line, the order in which the
 12.1652 +   capability lines appears is not significant; the server need not even
 12.1653 +   consistently return the same order.
 12.1654 +
 12.1655 +   While some capabilities are likely to be always available or never
 12.1656 +   available, others (notably extensions) will appear and disappear
 12.1657 +   depending on server state changes within the session or on external
 12.1658 +   events between sessions.  An NNTP client MAY cache the results of
 12.1659 +   this command, but MUST NOT rely on the correctness of any cached
 12.1660 +   results, whether from earlier in this session or from a previous
 12.1661 +   session, MUST cope gracefully with the cached status being out of
 12.1662 +   date, and SHOULD (if caching results) provide a way to force the
 12.1663 +   cached information to be refreshed.  Furthermore, a client MUST NOT
 12.1664 +   use cached results in relation to security, privacy, and
 12.1665 +   authentication extensions.  See Section 12.6 for further discussion
 12.1666 +   of this topic.
 12.1667 +
 12.1668 +   The keyword argument is not used by this specification.  It is
 12.1669 +   provided so that extensions or revisions to this specification can
 12.1670 +   include extra features for this command without requiring the
 12.1671 +   CAPABILITIES command to be used twice (once to determine if the extra
 12.1672 +   features are available, and a second time to make use of them).  If
 12.1673 +   the server does not recognise the argument (and it is a keyword), it
 12.1674 +   MUST respond with the 101 response code as if the argument had been
 12.1675 +   omitted.  If an argument is provided that the server does recognise,
 12.1676 +   it MAY use the 101 response code or MAY use some other response code
 12.1677 +
 12.1678 +
 12.1679 +
 12.1680 +Feather                     Standards Track                    [Page 30]
 12.1681 +
 12.1682 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1683 +
 12.1684 +
 12.1685 +   (which will be defined in the specification of that feature).  If the
 12.1686 +   argument is not a keyword, the 501 generic response code MUST be
 12.1687 +   returned.  The server MUST NOT generate any other response code to
 12.1688 +   the CAPABILITIES command.
 12.1689 +
 12.1690 +5.2.3.  Examples
 12.1691 +
 12.1692 +   Example of a minimal response (a read-only server):
 12.1693 +
 12.1694 +      [C] CAPABILITIES
 12.1695 +      [S] 101 Capability list:
 12.1696 +      [S] VERSION 2
 12.1697 +      [S] READER
 12.1698 +      [S] LIST ACTIVE NEWSGROUPS
 12.1699 +      [S] .
 12.1700 +
 12.1701 +   Example of a response from a server that has a range of facilities
 12.1702 +   and that also describes itself:
 12.1703 +
 12.1704 +      [C] CAPABILITIES
 12.1705 +      [S] 101 Capability list:
 12.1706 +      [S] VERSION 2
 12.1707 +      [S] READER
 12.1708 +      [S] IHAVE
 12.1709 +      [S] POST
 12.1710 +      [S] NEWNEWS
 12.1711 +      [S] LIST ACTIVE NEWSGROUPS ACTIVE.TIMES OVERVIEW.FMT
 12.1712 +      [S] IMPLEMENTATION INN 4.2 2004-12-25
 12.1713 +      [S] OVER MSGID
 12.1714 +      [S] STREAMING
 12.1715 +      [S] XSECRET
 12.1716 +      [S] .
 12.1717 +
 12.1718 +   Example of a server that supports more than one version of NNTP:
 12.1719 +
 12.1720 +      [C] CAPABILITIES
 12.1721 +      [S] 101 Capability list:
 12.1722 +      [S] VERSION 2 3
 12.1723 +      [S] READER
 12.1724 +      [S] LIST ACTIVE NEWSGROUPS
 12.1725 +      [S] .
 12.1726 +
 12.1727 +
 12.1728 +
 12.1729 +
 12.1730 +
 12.1731 +
 12.1732 +
 12.1733 +
 12.1734 +
 12.1735 +
 12.1736 +Feather                     Standards Track                    [Page 31]
 12.1737 +
 12.1738 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1739 +
 12.1740 +
 12.1741 +   Example of a client attempting to use a feature of the CAPABILITIES
 12.1742 +   command that the server does not support:
 12.1743 +
 12.1744 +      [C] CAPABILITIES AUTOUPDATE
 12.1745 +      [S] 101 Capability list:
 12.1746 +      [S] VERSION 2
 12.1747 +      [S] READER
 12.1748 +      [S] IHAVE
 12.1749 +      [S] LIST ACTIVE NEWSGROUPS OVERVIEW.FMT HEADERS
 12.1750 +      [S] OVER MSGID
 12.1751 +      [S] HDR
 12.1752 +      [S] NEWNEWS
 12.1753 +      [S] .
 12.1754 +
 12.1755 +5.3.  MODE READER
 12.1756 +
 12.1757 +5.3.1.  Usage
 12.1758 +
 12.1759 +   Indicating capability: MODE-READER
 12.1760 +
 12.1761 +   This command MUST NOT be pipelined.
 12.1762 +
 12.1763 +   Syntax
 12.1764 +     MODE READER
 12.1765 +
 12.1766 +   Responses
 12.1767 +     200    Posting allowed
 12.1768 +     201    Posting prohibited
 12.1769 +     502    Reading service permanently unavailable [1]
 12.1770 +
 12.1771 +   [1] Following a 502 response the server MUST immediately close the
 12.1772 +       connection.
 12.1773 +
 12.1774 +5.3.2.  Description
 12.1775 +
 12.1776 +   The MODE READER command instructs a mode-switching server to switch
 12.1777 +   modes, as described in Section 3.4.2.
 12.1778 +
 12.1779 +   If the server is mode-switching, it switches from its transit mode to
 12.1780 +   its reader mode, indicating this by changing the capability list
 12.1781 +   accordingly.  It MUST then return a 200 or 201 response with the same
 12.1782 +   meaning as for the initial greeting (as described in Section 5.1.1).
 12.1783 +   Note that the response need not be the same as that presented during
 12.1784 +   the initial greeting.  The client MUST NOT issue MODE READER more
 12.1785 +   than once in a session or after any security or privacy commands are
 12.1786 +   issued.  When the MODE READER command is issued, the server MAY reset
 12.1787 +   its state to that immediately after the initial connection before
 12.1788 +   switching mode.
 12.1789 +
 12.1790 +
 12.1791 +
 12.1792 +Feather                     Standards Track                    [Page 32]
 12.1793 +
 12.1794 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1795 +
 12.1796 +
 12.1797 +   If the server is not mode-switching, then the following apply:
 12.1798 +
 12.1799 +   o  If it advertises the READER capability, it MUST return a 200 or
 12.1800 +      201 response with the same meaning as for the initial greeting; in
 12.1801 +      this case, the command MUST NOT affect the server state in any
 12.1802 +      way.
 12.1803 +
 12.1804 +   o  If it does not advertise the READER capability, it MUST return a
 12.1805 +      502 response and then immediately close the connection.
 12.1806 +
 12.1807 +5.3.3.  Examples
 12.1808 +
 12.1809 +   Example of use of the MODE READER command on a transit-only server
 12.1810 +   (which therefore does not providing reading facilities):
 12.1811 +
 12.1812 +      [C] CAPABILITIES
 12.1813 +      [S] 101 Capability list:
 12.1814 +      [S] VERSION 2
 12.1815 +      [S] IHAVE
 12.1816 +      [S] .
 12.1817 +      [C] MODE READER
 12.1818 +      [S] 502 Transit service only
 12.1819 +      [Server closes connection.]
 12.1820 +
 12.1821 +   Example of use of the MODE READER command on a server that provides
 12.1822 +   reading facilities:
 12.1823 +
 12.1824 +      [C] CAPABILITIES
 12.1825 +      [S] 101 Capability list:
 12.1826 +      [S] VERSION 2
 12.1827 +      [S] READER
 12.1828 +      [S] LIST ACTIVE NEWSGROUPS
 12.1829 +      [S] .
 12.1830 +      [C] MODE READER
 12.1831 +      [S] 200 Reader mode, posting permitted
 12.1832 +      [C] IHAVE <i.am.an.article.you.have@example.com>
 12.1833 +      [S] 500 Permission denied
 12.1834 +      [C] GROUP misc.test
 12.1835 +      [S] 211 1234 3000234 3002322 misc.test
 12.1836 +
 12.1837 +   Note that in both of these situations, the client SHOULD NOT use MODE
 12.1838 +   READER.
 12.1839 +
 12.1840 +
 12.1841 +
 12.1842 +
 12.1843 +
 12.1844 +
 12.1845 +
 12.1846 +
 12.1847 +
 12.1848 +Feather                     Standards Track                    [Page 33]
 12.1849 +
 12.1850 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1851 +
 12.1852 +
 12.1853 +   Example of use of the MODE READER command on a mode-switching server:
 12.1854 +
 12.1855 +      [C] CAPABILITIES
 12.1856 +      [S] 101 Capability list:
 12.1857 +      [S] VERSION 2
 12.1858 +      [S] IHAVE
 12.1859 +      [S] MODE-READER
 12.1860 +      [S] .
 12.1861 +      [C] MODE READER
 12.1862 +      [S] 200 Reader mode, posting permitted
 12.1863 +      [C] CAPABILITIES
 12.1864 +      [S] 101 Capability list:
 12.1865 +      [S] VERSION 2
 12.1866 +      [S] READER
 12.1867 +      [S] NEWNEWS
 12.1868 +      [S] LIST ACTIVE NEWSGROUPS
 12.1869 +      [S] STARTTLS
 12.1870 +      [S] .
 12.1871 +
 12.1872 +   In this case, the server offers (but does not require) TLS privacy in
 12.1873 +   its reading mode but not in its transit mode.
 12.1874 +
 12.1875 +   Example of use of the MODE READER command where the client is not
 12.1876 +   permitted to post:
 12.1877 +
 12.1878 +      [C] MODE READER
 12.1879 +      [S] 201 NNTP Service Ready, posting prohibited
 12.1880 +
 12.1881 +5.4.  QUIT
 12.1882 +
 12.1883 +5.4.1.  Usage
 12.1884 +
 12.1885 +   This command is mandatory.
 12.1886 +
 12.1887 +   Syntax
 12.1888 +     QUIT
 12.1889 +
 12.1890 +   Responses
 12.1891 +     205    Connection closing
 12.1892 +
 12.1893 +5.4.2.  Description
 12.1894 +
 12.1895 +   The client uses the QUIT command to terminate the session.  The
 12.1896 +   server MUST acknowledge the QUIT command and then close the
 12.1897 +   connection to the client.  This is the preferred method for a client
 12.1898 +   to indicate that it has finished all of its transactions with the
 12.1899 +   NNTP server.
 12.1900 +
 12.1901 +
 12.1902 +
 12.1903 +
 12.1904 +Feather                     Standards Track                    [Page 34]
 12.1905 +
 12.1906 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1907 +
 12.1908 +
 12.1909 +   If a client simply disconnects (or if the connection times out or
 12.1910 +   some other fault occurs), the server MUST gracefully cease its
 12.1911 +   attempts to service the client, disconnecting from its end if
 12.1912 +   necessary.
 12.1913 +
 12.1914 +   The server MUST NOT generate any response code to the QUIT command
 12.1915 +   other than 205 or, if any arguments are provided, 501.
 12.1916 +
 12.1917 +5.4.3.  Examples
 12.1918 +
 12.1919 +      [C] QUIT
 12.1920 +      [S] 205 closing connection
 12.1921 +      [Server closes connection.]
 12.1922 +
 12.1923 +6.  Article Posting and Retrieval
 12.1924 +
 12.1925 +   News-reading clients have available a variety of mechanisms to
 12.1926 +   retrieve articles via NNTP.  The news articles are stored and indexed
 12.1927 +   using three types of keys.  The first type of key is the message-id
 12.1928 +   of an article and is globally unique.  The second type of key is
 12.1929 +   composed of a newsgroup name and an article number within that
 12.1930 +   newsgroup.  On a particular server, there MUST only be one article
 12.1931 +   with a given number within any newsgroup, and an article MUST NOT
 12.1932 +   have two different numbers in the same newsgroup.  An article can be
 12.1933 +   cross-posted to multiple newsgroups, so there may be multiple keys
 12.1934 +   that point to the same article on the same server; these MAY have
 12.1935 +   different numbers in each newsgroup.  However, this type of key is
 12.1936 +   not required to be globally unique, so the same key MAY refer to
 12.1937 +   different articles on different servers.  (Note that the terms
 12.1938 +   "group" and "newsgroup" are equivalent.)
 12.1939 +
 12.1940 +   The final type of key is the arrival timestamp, giving the time that
 12.1941 +   the article arrived at the server.  The server MUST ensure that
 12.1942 +   article numbers are issued in order of arrival timestamp; that is,
 12.1943 +   articles arriving later MUST have higher numbers than those that
 12.1944 +   arrive earlier.  The server SHOULD allocate the next sequential
 12.1945 +   unused number to each new article.
 12.1946 +
 12.1947 +   Article numbers MUST lie between 1 and 2,147,483,647, inclusive.  The
 12.1948 +   client and server MAY use leading zeroes in specifying article
 12.1949 +   numbers but MUST NOT use more than 16 digits.  In some situations,
 12.1950 +   the value zero replaces an article number to show some special
 12.1951 +   situation.
 12.1952 +
 12.1953 +   Note that it is likely that the article number limit of 2,147,483,647
 12.1954 +   will be increased by a future revision or extension to this
 12.1955 +   specification.  While servers MUST NOT send article numbers greater
 12.1956 +   than this current limit, client and server developers are advised to
 12.1957 +
 12.1958 +
 12.1959 +
 12.1960 +Feather                     Standards Track                    [Page 35]
 12.1961 +
 12.1962 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.1963 +
 12.1964 +
 12.1965 +   use internal structures and datatypes capable of handling larger
 12.1966 +   values in anticipation of such a change.
 12.1967 +
 12.1968 +6.1.  Group and Article Selection
 12.1969 +
 12.1970 +   The following commands are used to set the "currently selected
 12.1971 +   newsgroup" and the "current article number", which are used by
 12.1972 +   various commands.  At the start of an NNTP session, both of these
 12.1973 +   values are set to the special value "invalid".
 12.1974 +
 12.1975 +6.1.1.  GROUP
 12.1976 +
 12.1977 +6.1.1.1.  Usage
 12.1978 +
 12.1979 +   Indicating capability: READER
 12.1980 +
 12.1981 +   Syntax
 12.1982 +     GROUP group
 12.1983 +
 12.1984 +   Responses
 12.1985 +     211 number low high group     Group successfully selected
 12.1986 +     411                           No such newsgroup
 12.1987 +
 12.1988 +   Parameters
 12.1989 +     group     Name of newsgroup
 12.1990 +     number    Estimated number of articles in the group
 12.1991 +     low       Reported low water mark
 12.1992 +     high      Reported high water mark
 12.1993 +
 12.1994 +6.1.1.2.  Description
 12.1995 +
 12.1996 +   The GROUP command selects a newsgroup as the currently selected
 12.1997 +   newsgroup and returns summary information about it.
 12.1998 +
 12.1999 +   The required argument is the name of the newsgroup to be selected
 12.2000 +   (e.g., "news.software.nntp").  A list of valid newsgroups may be
 12.2001 +   obtained by using the LIST ACTIVE command (see Section 7.6.3).
 12.2002 +
 12.2003 +   The successful selection response will return the article numbers of
 12.2004 +   the first and last articles in the group at the moment of selection
 12.2005 +   (these numbers are referred to as the "reported low water mark" and
 12.2006 +   the "reported high water mark") and an estimate of the number of
 12.2007 +   articles in the group currently available.
 12.2008 +
 12.2009 +   If the group is not empty, the estimate MUST be at least the actual
 12.2010 +   number of articles available and MUST be no greater than one more
 12.2011 +   than the difference between the reported low and high water marks.
 12.2012 +   (Some implementations will actually count the number of articles
 12.2013 +
 12.2014 +
 12.2015 +
 12.2016 +Feather                     Standards Track                    [Page 36]
 12.2017 +
 12.2018 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2019 +
 12.2020 +
 12.2021 +   currently stored.  Others will just subtract the low water mark from
 12.2022 +   the high water mark and add one to get an estimate.)
 12.2023 +
 12.2024 +   If the group is empty, one of the following three situations will
 12.2025 +   occur.  Clients MUST accept all three cases; servers MUST NOT
 12.2026 +   represent an empty group in any other way.
 12.2027 +
 12.2028 +   o  The high water mark will be one less than the low water mark, and
 12.2029 +      the estimated article count will be zero.  Servers SHOULD use this
 12.2030 +      method to show an empty group.  This is the only time that the
 12.2031 +      high water mark can be less than the low water mark.
 12.2032 +
 12.2033 +   o  All three numbers will be zero.
 12.2034 +
 12.2035 +   o  The high water mark is greater than or equal to the low water
 12.2036 +      mark.  The estimated article count might be zero or non-zero; if
 12.2037 +      it is non-zero, the same requirements apply as for a non-empty
 12.2038 +      group.
 12.2039 +
 12.2040 +   The set of articles in a group may change after the GROUP command is
 12.2041 +   carried out:
 12.2042 +
 12.2043 +   o  Articles may be removed from the group.
 12.2044 +
 12.2045 +   o  Articles may be reinstated in the group with the same article
 12.2046 +      number, but those articles MUST have numbers no less than the
 12.2047 +      reported low water mark (note that this is a reinstatement of the
 12.2048 +      previous article, not a new article reusing the number).
 12.2049 +
 12.2050 +   o  New articles may be added with article numbers greater than the
 12.2051 +      reported high water mark.  (If an article that was the one with
 12.2052 +      the highest number has been removed and the high water mark has
 12.2053 +      been adjusted accordingly, the next new article will not have the
 12.2054 +      number one greater than the reported high water mark.)
 12.2055 +
 12.2056 +   Except when the group is empty and all three numbers are zero,
 12.2057 +   whenever a subsequent GROUP command for the same newsgroup is issued,
 12.2058 +   either by the same client or a different client, the reported low
 12.2059 +   water mark in the response MUST be no less than that in any previous
 12.2060 +   response for that newsgroup in this session, and it SHOULD be no less
 12.2061 +   than that in any previous response for that newsgroup ever sent to
 12.2062 +   any client.  Any failure to meet the latter condition SHOULD be
 12.2063 +   transient only.  The client may make use of the low water mark to
 12.2064 +   remove all remembered information about articles with lower numbers,
 12.2065 +   as these will never recur.  This includes the situation when the high
 12.2066 +   water mark is one less than the low water mark.  No similar
 12.2067 +   assumption can be made about the high water mark, as this can
 12.2068 +
 12.2069 +
 12.2070 +
 12.2071 +
 12.2072 +Feather                     Standards Track                    [Page 37]
 12.2073 +
 12.2074 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2075 +
 12.2076 +
 12.2077 +   decrease if an article is removed and then increase again if it is
 12.2078 +   reinstated or if new articles arrive.
 12.2079 +
 12.2080 +   When a valid group is selected by means of this command, the
 12.2081 +   currently selected newsgroup MUST be set to that group, and the
 12.2082 +   current article number MUST be set to the first article in the group
 12.2083 +   (this applies even if the group is already the currently selected
 12.2084 +   newsgroup).  If an empty newsgroup is selected, the current article
 12.2085 +   number is made invalid.  If an invalid group is specified, the
 12.2086 +   currently selected newsgroup and current article number MUST NOT be
 12.2087 +   changed.
 12.2088 +
 12.2089 +   The GROUP or LISTGROUP command (see Section 6.1.2) MUST be used by a
 12.2090 +   client, and a successful response received, before any other command
 12.2091 +   is used that depends on the value of the currently selected newsgroup
 12.2092 +   or current article number.
 12.2093 +
 12.2094 +   If the group specified is not available on the server, a 411 response
 12.2095 +   MUST be returned.
 12.2096 +
 12.2097 +6.1.1.3.  Examples
 12.2098 +
 12.2099 +   Example for a group known to the server:
 12.2100 +
 12.2101 +      [C] GROUP misc.test
 12.2102 +      [S] 211 1234 3000234 3002322 misc.test
 12.2103 +
 12.2104 +   Example for a group unknown to the server:
 12.2105 +
 12.2106 +      [C] GROUP example.is.sob.bradner.or.barber
 12.2107 +      [S] 411 example.is.sob.bradner.or.barber is unknown
 12.2108 +
 12.2109 +   Example of an empty group using the preferred response:
 12.2110 +
 12.2111 +      [C] GROUP example.currently.empty.newsgroup
 12.2112 +      [S] 211 0 4000 3999 example.currently.empty.newsgroup
 12.2113 +
 12.2114 +   Example of an empty group using an alternative response:
 12.2115 +
 12.2116 +      [C] GROUP example.currently.empty.newsgroup
 12.2117 +      [S] 211 0 0 0 example.currently.empty.newsgroup
 12.2118 +
 12.2119 +   Example of an empty group using a different alternative response:
 12.2120 +
 12.2121 +      [C] GROUP example.currently.empty.newsgroup
 12.2122 +      [S] 211 0 4000 4321 example.currently.empty.newsgroup
 12.2123 +
 12.2124 +
 12.2125 +
 12.2126 +
 12.2127 +
 12.2128 +Feather                     Standards Track                    [Page 38]
 12.2129 +
 12.2130 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2131 +
 12.2132 +
 12.2133 +   Example reselecting the currently selected newsgroup:
 12.2134 +
 12.2135 +      [C] GROUP misc.test
 12.2136 +      [S] 211 1234 234 567 misc.test
 12.2137 +      [C] STAT 444
 12.2138 +      [S] 223 444 <123456@example.net> retrieved
 12.2139 +      [C] GROUP misc.test
 12.2140 +      [S] 211 1234 234 567 misc.test
 12.2141 +      [C] STAT
 12.2142 +      [S] 223 234 <different@example.net> retrieved
 12.2143 +
 12.2144 +6.1.2.  LISTGROUP
 12.2145 +
 12.2146 +6.1.2.1.  Usage
 12.2147 +
 12.2148 +   Indicating capability: READER
 12.2149 +
 12.2150 +   Syntax
 12.2151 +     LISTGROUP [group [range]]
 12.2152 +
 12.2153 +   Responses
 12.2154 +     211 number low high group     Article numbers follow (multi-line)
 12.2155 +     411                           No such newsgroup
 12.2156 +     412                           No newsgroup selected [1]
 12.2157 +
 12.2158 +   Parameters
 12.2159 +     group     Name of newsgroup
 12.2160 +     range     Range of articles to report
 12.2161 +     number    Estimated number of articles in the group
 12.2162 +     low       Reported low water mark
 12.2163 +     high      Reported high water mark
 12.2164 +
 12.2165 +   [1] The 412 response can only occur if no group has been specified.
 12.2166 +
 12.2167 +6.1.2.2.  Description
 12.2168 +
 12.2169 +   The LISTGROUP command selects a newsgroup in the same manner as the
 12.2170 +   GROUP command (see Section 6.1.1) but also provides a list of article
 12.2171 +   numbers in the newsgroup.  If no group is specified, the currently
 12.2172 +   selected newsgroup is used.
 12.2173 +
 12.2174 +   On success, a list of article numbers is returned as a multi-line
 12.2175 +   data block following the 211 response code (the arguments on the
 12.2176 +   initial response line are the same as for the GROUP command).  The
 12.2177 +   list contains one number per line and is in numerical order.  It
 12.2178 +   lists precisely those articles that exist in the group at the moment
 12.2179 +   of selection (therefore, an empty group produces an empty list).  If
 12.2180 +   the optional range argument is specified, only articles within the
 12.2181 +
 12.2182 +
 12.2183 +
 12.2184 +Feather                     Standards Track                    [Page 39]
 12.2185 +
 12.2186 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2187 +
 12.2188 +
 12.2189 +   range are included in the list (therefore, the list MAY be empty even
 12.2190 +   if the group is not).
 12.2191 +
 12.2192 +   The range argument may be any of the following:
 12.2193 +
 12.2194 +   o  An article number.
 12.2195 +
 12.2196 +   o  An article number followed by a dash to indicate all following.
 12.2197 +
 12.2198 +   o  An article number followed by a dash followed by another article
 12.2199 +      number.
 12.2200 +
 12.2201 +   In the last case, if the second number is less than the first number,
 12.2202 +   then the range contains no articles.  Omitting the range is
 12.2203 +   equivalent to the range 1- being specified.
 12.2204 +
 12.2205 +   If the group specified is not available on the server, a 411 response
 12.2206 +   MUST be returned.  If no group is specified and the currently
 12.2207 +   selected newsgroup is invalid, a 412 response MUST be returned.
 12.2208 +
 12.2209 +   Except that the group argument is optional, that a range argument can
 12.2210 +   be specified, and that a multi-line data block follows the 211
 12.2211 +   response code, the LISTGROUP command is identical to the GROUP
 12.2212 +   command.  In particular, when successful, the command sets the
 12.2213 +   current article number to the first article in the group, if any,
 12.2214 +   even if this is not within the range specified by the second
 12.2215 +   argument.
 12.2216 +
 12.2217 +   Note that the range argument is a new feature in this specification
 12.2218 +   and servers that do not support CAPABILITIES (and therefore do not
 12.2219 +   conform to this specification) are unlikely to support it.
 12.2220 +
 12.2221 +6.1.2.3.  Examples
 12.2222 +
 12.2223 +   Example of LISTGROUP being used to select a group:
 12.2224 +
 12.2225 +      [C] LISTGROUP misc.test
 12.2226 +      [S] 211 2000 3000234 3002322 misc.test list follows
 12.2227 +      [S] 3000234
 12.2228 +      [S] 3000237
 12.2229 +      [S] 3000238
 12.2230 +      [S] 3000239
 12.2231 +      [S] 3002322
 12.2232 +      [S] .
 12.2233 +
 12.2234 +
 12.2235 +
 12.2236 +
 12.2237 +
 12.2238 +
 12.2239 +
 12.2240 +Feather                     Standards Track                    [Page 40]
 12.2241 +
 12.2242 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2243 +
 12.2244 +
 12.2245 +   Example of LISTGROUP on an empty group:
 12.2246 +
 12.2247 +      [C] LISTGROUP example.empty.newsgroup
 12.2248 +      [S] 211 0 0 0 example.empty.newsgroup list follows
 12.2249 +      [S] .
 12.2250 +
 12.2251 +   Example of LISTGROUP on a valid, currently selected newsgroup:
 12.2252 +
 12.2253 +      [C] GROUP misc.test
 12.2254 +      [S] 211 2000 3000234 3002322 misc.test
 12.2255 +      [C] LISTGROUP
 12.2256 +      [S] 211 2000 3000234 3002322 misc.test list follows
 12.2257 +      [S] 3000234
 12.2258 +      [S] 3000237
 12.2259 +      [S] 3000238
 12.2260 +      [S] 3000239
 12.2261 +      [S] 3002322
 12.2262 +      [S] .
 12.2263 +
 12.2264 +   Example of LISTGROUP with a range:
 12.2265 +
 12.2266 +      [C] LISTGROUP misc.test 3000238-3000248
 12.2267 +      [S] 211 2000 3000234 3002322 misc.test list follows
 12.2268 +      [S] 3000238
 12.2269 +      [S] 3000239
 12.2270 +      [S] .
 12.2271 +
 12.2272 +   Example of LISTGROUP with an empty range:
 12.2273 +
 12.2274 +      [C] LISTGROUP misc.test 12345678-
 12.2275 +      [S] 211 2000 3000234 3002322 misc.test list follows
 12.2276 +      [S] .
 12.2277 +
 12.2278 +   Example of LISTGROUP with an invalid range:
 12.2279 +
 12.2280 +      [C] LISTGROUP misc.test 9999-111
 12.2281 +      [S] 211 2000 3000234 3002322 misc.test list follows
 12.2282 +      [S] .
 12.2283 +
 12.2284 +
 12.2285 +
 12.2286 +
 12.2287 +
 12.2288 +
 12.2289 +
 12.2290 +
 12.2291 +
 12.2292 +
 12.2293 +
 12.2294 +
 12.2295 +
 12.2296 +Feather                     Standards Track                    [Page 41]
 12.2297 +
 12.2298 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2299 +
 12.2300 +
 12.2301 +6.1.3.  LAST
 12.2302 +
 12.2303 +6.1.3.1.  Usage
 12.2304 +
 12.2305 +   Indicating capability: READER
 12.2306 +
 12.2307 +   Syntax
 12.2308 +     LAST
 12.2309 +
 12.2310 +   Responses
 12.2311 +     223 n message-id    Article found
 12.2312 +     412                 No newsgroup selected
 12.2313 +     420                 Current article number is invalid
 12.2314 +     422                 No previous article in this group
 12.2315 +
 12.2316 +   Parameters
 12.2317 +     n             Article number
 12.2318 +     message-id    Article message-id
 12.2319 +
 12.2320 +6.1.3.2.  Description
 12.2321 +
 12.2322 +   If the currently selected newsgroup is valid, the current article
 12.2323 +   number MUST be set to the previous article in that newsgroup (that
 12.2324 +   is, the highest existing article number less than the current article
 12.2325 +   number).  If successful, a response indicating the new current
 12.2326 +   article number and the message-id of that article MUST be returned.
 12.2327 +   No article text is sent in response to this command.
 12.2328 +
 12.2329 +   There MAY be no previous article in the group, although the current
 12.2330 +   article number is not the reported low water mark.  There MUST NOT be
 12.2331 +   a previous article when the current article number is the reported
 12.2332 +   low water mark.
 12.2333 +
 12.2334 +   Because articles can be removed and added, the results of multiple
 12.2335 +   LAST and NEXT commands MAY not be consistent over the life of a
 12.2336 +   particular NNTP session.
 12.2337 +
 12.2338 +   If the current article number is already the first article of the
 12.2339 +   newsgroup, a 422 response MUST be returned.  If the current article
 12.2340 +   number is invalid, a 420 response MUST be returned.  If the currently
 12.2341 +   selected newsgroup is invalid, a 412 response MUST be returned.  In
 12.2342 +   all three cases, the currently selected newsgroup and current article
 12.2343 +   number MUST NOT be altered.
 12.2344 +
 12.2345 +
 12.2346 +
 12.2347 +
 12.2348 +
 12.2349 +
 12.2350 +
 12.2351 +
 12.2352 +Feather                     Standards Track                    [Page 42]
 12.2353 +
 12.2354 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2355 +
 12.2356 +
 12.2357 +6.1.3.3.  Examples
 12.2358 +
 12.2359 +   Example of a successful article retrieval using LAST:
 12.2360 +
 12.2361 +      [C] GROUP misc.test
 12.2362 +      [S] 211 1234 3000234 3002322 misc.test
 12.2363 +      [C] NEXT
 12.2364 +      [S] 223 3000237 <668929@example.org> retrieved
 12.2365 +      [C] LAST
 12.2366 +      [S] 223 3000234 <45223423@example.com> retrieved
 12.2367 +
 12.2368 +   Example of an attempt to retrieve an article without having selected
 12.2369 +   a group (via the GROUP command) first:
 12.2370 +
 12.2371 +      [Assumes currently selected newsgroup is invalid.]
 12.2372 +      [C] LAST
 12.2373 +      [S] 412 no newsgroup selected
 12.2374 +
 12.2375 +   Example of an attempt to retrieve an article using the LAST command
 12.2376 +   when the current article number is that of the first article in the
 12.2377 +   group:
 12.2378 +
 12.2379 +      [C] GROUP misc.test
 12.2380 +      [S] 211 1234 3000234 3002322 misc.test
 12.2381 +      [C] LAST
 12.2382 +      [S] 422 No previous article to retrieve
 12.2383 +
 12.2384 +   Example of an attempt to retrieve an article using the LAST command
 12.2385 +   when the currently selected newsgroup is empty:
 12.2386 +
 12.2387 +      [C] GROUP example.empty.newsgroup
 12.2388 +      [S] 211 0 0 0 example.empty.newsgroup
 12.2389 +      [C] LAST
 12.2390 +      [S] 420 No current article selected
 12.2391 +
 12.2392 +
 12.2393 +
 12.2394 +
 12.2395 +
 12.2396 +
 12.2397 +
 12.2398 +
 12.2399 +
 12.2400 +
 12.2401 +
 12.2402 +
 12.2403 +
 12.2404 +
 12.2405 +
 12.2406 +
 12.2407 +
 12.2408 +Feather                     Standards Track                    [Page 43]
 12.2409 +
 12.2410 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2411 +
 12.2412 +
 12.2413 +6.1.4.  NEXT
 12.2414 +
 12.2415 +6.1.4.1.  Usage
 12.2416 +
 12.2417 +   Indicating capability: READER
 12.2418 +
 12.2419 +   Syntax
 12.2420 +     NEXT
 12.2421 +
 12.2422 +   Responses
 12.2423 +     223 n message-id    Article found
 12.2424 +     412                 No newsgroup selected
 12.2425 +     420                 Current article number is invalid
 12.2426 +     421                 No next article in this group
 12.2427 +
 12.2428 +   Parameters
 12.2429 +     n             Article number
 12.2430 +     message-id    Article message-id
 12.2431 +
 12.2432 +6.1.4.2.  Description
 12.2433 +
 12.2434 +   If the currently selected newsgroup is valid, the current article
 12.2435 +   number MUST be set to the next article in that newsgroup (that is,
 12.2436 +   the lowest existing article number greater than the current article
 12.2437 +   number).  If successful, a response indicating the new current
 12.2438 +   article number and the message-id of that article MUST be returned.
 12.2439 +   No article text is sent in response to this command.
 12.2440 +
 12.2441 +   If the current article number is already the last article of the
 12.2442 +   newsgroup, a 421 response MUST be returned.  In all other aspects
 12.2443 +   (apart, of course, from the lack of 422 response), this command is
 12.2444 +   identical to the LAST command (Section 6.1.3).
 12.2445 +
 12.2446 +6.1.4.3.  Examples
 12.2447 +
 12.2448 +   Example of a successful article retrieval using NEXT:
 12.2449 +
 12.2450 +      [C] GROUP misc.test
 12.2451 +      [S] 211 1234 3000234 3002322 misc.test
 12.2452 +      [C] NEXT
 12.2453 +      [S] 223 3000237 <668929@example.org> retrieved
 12.2454 +
 12.2455 +
 12.2456 +
 12.2457 +
 12.2458 +
 12.2459 +
 12.2460 +
 12.2461 +
 12.2462 +
 12.2463 +
 12.2464 +Feather                     Standards Track                    [Page 44]
 12.2465 +
 12.2466 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2467 +
 12.2468 +
 12.2469 +   Example of an attempt to retrieve an article without having selected
 12.2470 +   a group (via the GROUP command) first:
 12.2471 +
 12.2472 +      [Assumes currently selected newsgroup is invalid.]
 12.2473 +      [C] NEXT
 12.2474 +      [S] 412 no newsgroup selected
 12.2475 +
 12.2476 +   Example of an attempt to retrieve an article using the NEXT command
 12.2477 +   when the current article number is that of the last article in the
 12.2478 +   group:
 12.2479 +
 12.2480 +      [C] GROUP misc.test
 12.2481 +      [S] 211 1234 3000234 3002322 misc.test
 12.2482 +      [C] STAT 3002322
 12.2483 +      [S] 223 3002322 <411@example.net> retrieved
 12.2484 +      [C] NEXT
 12.2485 +      [S] 421 No next article to retrieve
 12.2486 +
 12.2487 +   Example of an attempt to retrieve an article using the NEXT command
 12.2488 +   when the currently selected newsgroup is empty:
 12.2489 +
 12.2490 +      [C] GROUP example.empty.newsgroup
 12.2491 +      [S] 211 0 0 0 example.empty.newsgroup
 12.2492 +      [C] NEXT
 12.2493 +      [S] 420 No current article selected
 12.2494 +
 12.2495 +6.2.  Retrieval of Articles and Article Sections
 12.2496 +
 12.2497 +   The ARTICLE, BODY, HEAD, and STAT commands are very similar.  They
 12.2498 +   differ only in the parts of the article that are presented to the
 12.2499 +   client and in the successful response code.  The ARTICLE command is
 12.2500 +   described here in full, while the other three commands are described
 12.2501 +   in terms of the differences.  As specified in Section 3.6, an article
 12.2502 +   consists of two parts: the article headers and the article body.
 12.2503 +
 12.2504 +   When responding to one of these commands, the server MUST present the
 12.2505 +   entire article or appropriate part and MUST NOT attempt to alter or
 12.2506 +   translate it in any way.
 12.2507 +
 12.2508 +
 12.2509 +
 12.2510 +
 12.2511 +
 12.2512 +
 12.2513 +
 12.2514 +
 12.2515 +
 12.2516 +
 12.2517 +
 12.2518 +
 12.2519 +
 12.2520 +Feather                     Standards Track                    [Page 45]
 12.2521 +
 12.2522 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2523 +
 12.2524 +
 12.2525 +6.2.1.  ARTICLE
 12.2526 +
 12.2527 +6.2.1.1.  Usage
 12.2528 +
 12.2529 +   Indicating capability: READER
 12.2530 +
 12.2531 +   Syntax
 12.2532 +     ARTICLE message-id
 12.2533 +     ARTICLE number
 12.2534 +     ARTICLE
 12.2535 +
 12.2536 +   Responses
 12.2537 +
 12.2538 +   First form (message-id specified)
 12.2539 +     220 0|n message-id    Article follows (multi-line)
 12.2540 +     430                   No article with that message-id
 12.2541 +
 12.2542 +   Second form (article number specified)
 12.2543 +     220 n message-id      Article follows (multi-line)
 12.2544 +     412                   No newsgroup selected
 12.2545 +     423                   No article with that number
 12.2546 +
 12.2547 +   Third form (current article number used)
 12.2548 +     220 n message-id      Article follows (multi-line)
 12.2549 +     412                   No newsgroup selected
 12.2550 +     420                   Current article number is invalid
 12.2551 +
 12.2552 +   Parameters
 12.2553 +     number        Requested article number
 12.2554 +     n             Returned article number
 12.2555 +     message-id    Article message-id
 12.2556 +
 12.2557 +6.2.1.2.  Description
 12.2558 +
 12.2559 +   The ARTICLE command selects an article according to the arguments and
 12.2560 +   presents the entire article (that is, the headers, an empty line, and
 12.2561 +   the body, in that order) to the client.  The command has three forms.
 12.2562 +
 12.2563 +   In the first form, a message-id is specified, and the server presents
 12.2564 +   the article with that message-id.  In this case, the server MUST NOT
 12.2565 +   alter the currently selected newsgroup or current article number.
 12.2566 +   This is both to facilitate the presentation of articles that may be
 12.2567 +   referenced within another article being read, and because of the
 12.2568 +   semantic difficulties of determining the proper sequence and
 12.2569 +   membership of an article that may have been cross-posted to more than
 12.2570 +   one newsgroup.
 12.2571 +
 12.2572 +
 12.2573 +
 12.2574 +
 12.2575 +
 12.2576 +Feather                     Standards Track                    [Page 46]
 12.2577 +
 12.2578 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2579 +
 12.2580 +
 12.2581 +   In the response, the article number MUST be replaced with zero,
 12.2582 +   unless there is a currently selected newsgroup and the article is
 12.2583 +   present in that group, in which case the server MAY use the article's
 12.2584 +   number in that group.  (The server is not required to determine
 12.2585 +   whether the article is in the currently selected newsgroup or, if so,
 12.2586 +   what article number it has; the client MUST always be prepared for
 12.2587 +   zero to be specified.)  The server MUST NOT provide an article number
 12.2588 +   unless use of that number in a second ARTICLE command immediately
 12.2589 +   following this one would return the same article.  Even if the server
 12.2590 +   chooses to return article numbers in these circumstances, it need not
 12.2591 +   do so consistently; it MAY return zero to any such command (also see
 12.2592 +   the STAT examples, Section 6.2.4.3).
 12.2593 +
 12.2594 +   In the second form, an article number is specified.  If there is an
 12.2595 +   article with that number in the currently selected newsgroup, the
 12.2596 +   server MUST set the current article number to that number.
 12.2597 +
 12.2598 +   In the third form, the article indicated by the current article
 12.2599 +   number in the currently selected newsgroup is used.
 12.2600 +
 12.2601 +   Note that a previously valid article number MAY become invalid if the
 12.2602 +   article has been removed.  A previously invalid article number MAY
 12.2603 +   become valid if the article has been reinstated, but this article
 12.2604 +   number MUST be no less than the reported low water mark for that
 12.2605 +   group.
 12.2606 +
 12.2607 +   The server MUST NOT change the currently selected newsgroup as a
 12.2608 +   result of this command.  The server MUST NOT change the current
 12.2609 +   article number except when an article number argument was provided
 12.2610 +   and the article exists; in particular, it MUST NOT change it
 12.2611 +   following an unsuccessful response.
 12.2612 +
 12.2613 +   Since the message-id is unique for each article, it may be used by a
 12.2614 +   client to skip duplicate displays of articles that have been posted
 12.2615 +   more than once, or to more than one newsgroup.
 12.2616 +
 12.2617 +   The article is returned as a multi-line data block following the 220
 12.2618 +   response code.
 12.2619 +
 12.2620 +   If the argument is a message-id and no such article exists, a 430
 12.2621 +   response MUST be returned.  If the argument is a number or is omitted
 12.2622 +   and the currently selected newsgroup is invalid, a 412 response MUST
 12.2623 +   be returned.  If the argument is a number and that article does not
 12.2624 +   exist in the currently selected newsgroup, a 423 response MUST be
 12.2625 +   returned.  If the argument is omitted and the current article number
 12.2626 +   is invalid, a 420 response MUST be returned.
 12.2627 +
 12.2628 +
 12.2629 +
 12.2630 +
 12.2631 +
 12.2632 +Feather                     Standards Track                    [Page 47]
 12.2633 +
 12.2634 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2635 +
 12.2636 +
 12.2637 +6.2.1.3.  Examples
 12.2638 +
 12.2639 +   Example of a successful retrieval of an article (explicitly not using
 12.2640 +   an article number):
 12.2641 +
 12.2642 +      [C] GROUP misc.test
 12.2643 +      [S] 211 1234 3000234 3002322 misc.test
 12.2644 +      [C] ARTICLE
 12.2645 +      [S] 220 3000234 <45223423@example.com>
 12.2646 +      [S] Path: pathost!demo!whitehouse!not-for-mail
 12.2647 +      [S] From: "Demo User" <nobody@example.net>
 12.2648 +      [S] Newsgroups: misc.test
 12.2649 +      [S] Subject: I am just a test article
 12.2650 +      [S] Date: 6 Oct 1998 04:38:40 -0500
 12.2651 +      [S] Organization: An Example Net, Uncertain, Texas
 12.2652 +      [S] Message-ID: <45223423@example.com>
 12.2653 +      [S]
 12.2654 +      [S] This is just a test article.
 12.2655 +      [S] .
 12.2656 +
 12.2657 +   Example of a successful retrieval of an article by message-id:
 12.2658 +
 12.2659 +      [C] ARTICLE <45223423@example.com>
 12.2660 +      [S] 220 0 <45223423@example.com>
 12.2661 +      [S] Path: pathost!demo!whitehouse!not-for-mail
 12.2662 +      [S] From: "Demo User" <nobody@example.net>
 12.2663 +      [S] Newsgroups: misc.test
 12.2664 +      [S] Subject: I am just a test article
 12.2665 +      [S] Date: 6 Oct 1998 04:38:40 -0500
 12.2666 +      [S] Organization: An Example Net, Uncertain, Texas
 12.2667 +      [S] Message-ID: <45223423@example.com>
 12.2668 +      [S]
 12.2669 +      [S] This is just a test article.
 12.2670 +      [S] .
 12.2671 +
 12.2672 +   Example of an unsuccessful retrieval of an article by message-id:
 12.2673 +
 12.2674 +      [C] ARTICLE <i.am.not.there@example.com>
 12.2675 +      [S] 430 No Such Article Found
 12.2676 +
 12.2677 +   Example of an unsuccessful retrieval of an article by number:
 12.2678 +
 12.2679 +      [C] GROUP misc.test
 12.2680 +      [S] 211 1234 3000234 3002322 news.groups
 12.2681 +      [C] ARTICLE 300256
 12.2682 +      [S] 423 No article with that number
 12.2683 +
 12.2684 +
 12.2685 +
 12.2686 +
 12.2687 +
 12.2688 +Feather                     Standards Track                    [Page 48]
 12.2689 +
 12.2690 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2691 +
 12.2692 +
 12.2693 +   Example of an unsuccessful retrieval of an article by number because
 12.2694 +   no newsgroup was selected first:
 12.2695 +
 12.2696 +      [Assumes currently selected newsgroup is invalid.]
 12.2697 +      [C] ARTICLE 300256
 12.2698 +      [S] 412 No newsgroup selected
 12.2699 +
 12.2700 +   Example of an attempt to retrieve an article when the currently
 12.2701 +   selected newsgroup is empty:
 12.2702 +
 12.2703 +      [C] GROUP example.empty.newsgroup
 12.2704 +      [S] 211 0 0 0 example.empty.newsgroup
 12.2705 +      [C] ARTICLE
 12.2706 +      [S] 420 No current article selected
 12.2707 +
 12.2708 +6.2.2.  HEAD
 12.2709 +
 12.2710 +6.2.2.1.  Usage
 12.2711 +
 12.2712 +   This command is mandatory.
 12.2713 +
 12.2714 +   Syntax
 12.2715 +     HEAD message-id
 12.2716 +     HEAD number
 12.2717 +     HEAD
 12.2718 +
 12.2719 +   Responses
 12.2720 +
 12.2721 +   First form (message-id specified)
 12.2722 +     221 0|n message-id    Headers follow (multi-line)
 12.2723 +     430                   No article with that message-id
 12.2724 +
 12.2725 +   Second form (article number specified)
 12.2726 +     221 n message-id      Headers follow (multi-line)
 12.2727 +     412                   No newsgroup selected
 12.2728 +     423                   No article with that number
 12.2729 +
 12.2730 +   Third form (current article number used)
 12.2731 +     221 n message-id      Headers follow (multi-line)
 12.2732 +     412                   No newsgroup selected
 12.2733 +     420                   Current article number is invalid
 12.2734 +
 12.2735 +   Parameters
 12.2736 +     number        Requested article number
 12.2737 +     n             Returned article number
 12.2738 +     message-id    Article message-id
 12.2739 +
 12.2740 +
 12.2741 +
 12.2742 +
 12.2743 +
 12.2744 +Feather                     Standards Track                    [Page 49]
 12.2745 +
 12.2746 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2747 +
 12.2748 +
 12.2749 +6.2.2.2.  Description
 12.2750 +
 12.2751 +   The HEAD command behaves identically to the ARTICLE command except
 12.2752 +   that, if the article exists, the response code is 221 instead of 220
 12.2753 +   and only the headers are presented (the empty line separating the
 12.2754 +   headers and body MUST NOT be included).
 12.2755 +
 12.2756 +6.2.2.3.  Examples
 12.2757 +
 12.2758 +   Example of a successful retrieval of the headers of an article
 12.2759 +   (explicitly not using an article number):
 12.2760 +
 12.2761 +      [C] GROUP misc.test
 12.2762 +      [S] 211 1234 3000234 3002322 misc.test
 12.2763 +      [C] HEAD
 12.2764 +      [S] 221 3000234 <45223423@example.com>
 12.2765 +      [S] Path: pathost!demo!whitehouse!not-for-mail
 12.2766 +      [S] From: "Demo User" <nobody@example.net>
 12.2767 +      [S] Newsgroups: misc.test
 12.2768 +      [S] Subject: I am just a test article
 12.2769 +      [S] Date: 6 Oct 1998 04:38:40 -0500
 12.2770 +      [S] Organization: An Example Net, Uncertain, Texas
 12.2771 +      [S] Message-ID: <45223423@example.com>
 12.2772 +      [S] .
 12.2773 +
 12.2774 +   Example of a successful retrieval of the headers of an article by
 12.2775 +   message-id:
 12.2776 +
 12.2777 +      [C] HEAD <45223423@example.com>
 12.2778 +      [S] 221 0 <45223423@example.com>
 12.2779 +      [S] Path: pathost!demo!whitehouse!not-for-mail
 12.2780 +      [S] From: "Demo User" <nobody@example.net>
 12.2781 +      [S] Newsgroups: misc.test
 12.2782 +      [S] Subject: I am just a test article
 12.2783 +      [S] Date: 6 Oct 1998 04:38:40 -0500
 12.2784 +      [S] Organization: An Example Net, Uncertain, Texas
 12.2785 +      [S] Message-ID: <45223423@example.com>
 12.2786 +      [S] .
 12.2787 +
 12.2788 +   Example of an unsuccessful retrieval of the headers of an article by
 12.2789 +   message-id:
 12.2790 +
 12.2791 +      [C] HEAD <i.am.not.there@example.com>
 12.2792 +      [S] 430 No Such Article Found
 12.2793 +
 12.2794 +
 12.2795 +
 12.2796 +
 12.2797 +
 12.2798 +
 12.2799 +
 12.2800 +Feather                     Standards Track                    [Page 50]
 12.2801 +
 12.2802 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2803 +
 12.2804 +
 12.2805 +   Example of an unsuccessful retrieval of the headers of an article by
 12.2806 +   number:
 12.2807 +
 12.2808 +      [C] GROUP misc.test
 12.2809 +      [S] 211 1234 3000234 3002322 misc.test
 12.2810 +      [C] HEAD 300256
 12.2811 +      [S] 423 No article with that number
 12.2812 +
 12.2813 +   Example of an unsuccessful retrieval of the headers of an article by
 12.2814 +   number because no newsgroup was selected first:
 12.2815 +
 12.2816 +      [Assumes currently selected newsgroup is invalid.]
 12.2817 +      [C] HEAD 300256
 12.2818 +      [S] 412 No newsgroup selected
 12.2819 +
 12.2820 +   Example of an attempt to retrieve the headers of an article when the
 12.2821 +   currently selected newsgroup is empty:
 12.2822 +
 12.2823 +      [C] GROUP example.empty.newsgroup
 12.2824 +      [S] 211 0 0 0 example.empty.newsgroup
 12.2825 +      [C] HEAD
 12.2826 +      [S] 420 No current article selected
 12.2827 +
 12.2828 +6.2.3.  BODY
 12.2829 +
 12.2830 +6.2.3.1.  Usage
 12.2831 +
 12.2832 +   Indicating capability: READER
 12.2833 +
 12.2834 +   Syntax
 12.2835 +     BODY message-id
 12.2836 +     BODY number
 12.2837 +     BODY
 12.2838 +
 12.2839 +   Responses
 12.2840 +
 12.2841 +   First form (message-id specified)
 12.2842 +     222 0|n message-id    Body follows (multi-line)
 12.2843 +     430                   No article with that message-id
 12.2844 +
 12.2845 +   Second form (article number specified)
 12.2846 +     222 n message-id      Body follows (multi-line)
 12.2847 +     412                   No newsgroup selected
 12.2848 +     423                   No article with that number
 12.2849 +
 12.2850 +
 12.2851 +
 12.2852 +
 12.2853 +
 12.2854 +
 12.2855 +
 12.2856 +Feather                     Standards Track                    [Page 51]
 12.2857 +
 12.2858 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2859 +
 12.2860 +
 12.2861 +   Third form (current article number used)
 12.2862 +     222 n message-id      Body follows (multi-line)
 12.2863 +     412                   No newsgroup selected
 12.2864 +     420                   Current article number is invalid
 12.2865 +
 12.2866 +   Parameters
 12.2867 +     number        Requested article number
 12.2868 +     n             Returned article number
 12.2869 +     message-id    Article message-id
 12.2870 +
 12.2871 +6.2.3.2.  Description
 12.2872 +
 12.2873 +   The BODY command behaves identically to the ARTICLE command except
 12.2874 +   that, if the article exists, the response code is 222 instead of 220
 12.2875 +   and only the body is presented (the empty line separating the headers
 12.2876 +   and body MUST NOT be included).
 12.2877 +
 12.2878 +6.2.3.3.  Examples
 12.2879 +
 12.2880 +   Example of a successful retrieval of the body of an article
 12.2881 +   (explicitly not using an article number):
 12.2882 +
 12.2883 +      [C] GROUP misc.test
 12.2884 +      [S] 211 1234 3000234 3002322 misc.test
 12.2885 +      [C] BODY
 12.2886 +      [S] 222 3000234 <45223423@example.com>
 12.2887 +      [S] This is just a test article.
 12.2888 +      [S] .
 12.2889 +
 12.2890 +   Example of a successful retrieval of the body of an article by
 12.2891 +   message-id:
 12.2892 +
 12.2893 +      [C] BODY <45223423@example.com>
 12.2894 +      [S] 222 0 <45223423@example.com>
 12.2895 +      [S] This is just a test article.
 12.2896 +      [S] .
 12.2897 +
 12.2898 +   Example of an unsuccessful retrieval of the body of an article by
 12.2899 +   message-id:
 12.2900 +
 12.2901 +      [C] BODY <i.am.not.there@example.com>
 12.2902 +      [S] 430 No Such Article Found
 12.2903 +
 12.2904 +
 12.2905 +
 12.2906 +
 12.2907 +
 12.2908 +
 12.2909 +
 12.2910 +
 12.2911 +
 12.2912 +Feather                     Standards Track                    [Page 52]
 12.2913 +
 12.2914 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2915 +
 12.2916 +
 12.2917 +   Example of an unsuccessful retrieval of the body of an article by
 12.2918 +   number:
 12.2919 +
 12.2920 +      [C] GROUP misc.test
 12.2921 +      [S] 211 1234 3000234 3002322 misc.test
 12.2922 +      [C] BODY 300256
 12.2923 +      [S] 423 No article with that number
 12.2924 +
 12.2925 +   Example of an unsuccessful retrieval of the body of an article by
 12.2926 +   number because no newsgroup was selected first:
 12.2927 +
 12.2928 +      [Assumes currently selected newsgroup is invalid.]
 12.2929 +      [C] BODY 300256
 12.2930 +      [S] 412 No newsgroup selected
 12.2931 +
 12.2932 +   Example of an attempt to retrieve the body of an article when the
 12.2933 +   currently selected newsgroup is empty:
 12.2934 +
 12.2935 +      [C] GROUP example.empty.newsgroup
 12.2936 +      [S] 211 0 0 0 example.empty.newsgroup
 12.2937 +      [C] BODY
 12.2938 +      [S] 420 No current article selected
 12.2939 +
 12.2940 +6.2.4.  STAT
 12.2941 +
 12.2942 +6.2.4.1.  Usage
 12.2943 +
 12.2944 +   This command is mandatory.
 12.2945 +
 12.2946 +   Syntax
 12.2947 +     STAT message-id
 12.2948 +     STAT number
 12.2949 +     STAT
 12.2950 +
 12.2951 +   Responses
 12.2952 +
 12.2953 +   First form (message-id specified)
 12.2954 +     223 0|n message-id    Article exists
 12.2955 +     430                   No article with that message-id
 12.2956 +
 12.2957 +   Second form (article number specified)
 12.2958 +     223 n message-id      Article exists
 12.2959 +     412                   No newsgroup selected
 12.2960 +     423                   No article with that number
 12.2961 +
 12.2962 +
 12.2963 +
 12.2964 +
 12.2965 +
 12.2966 +
 12.2967 +
 12.2968 +Feather                     Standards Track                    [Page 53]
 12.2969 +
 12.2970 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.2971 +
 12.2972 +
 12.2973 +   Third form (current article number used)
 12.2974 +     223 n message-id      Article exists
 12.2975 +     412                   No newsgroup selected
 12.2976 +     420                   Current article number is invalid
 12.2977 +
 12.2978 +   Parameters
 12.2979 +     number        Requested article number
 12.2980 +     n             Returned article number
 12.2981 +     message-id    Article message-id
 12.2982 +
 12.2983 +6.2.4.2.  Description
 12.2984 +
 12.2985 +   The STAT command behaves identically to the ARTICLE command except
 12.2986 +   that, if the article exists, it is NOT presented to the client and
 12.2987 +   the response code is 223 instead of 220.  Note that the response is
 12.2988 +   NOT multi-line.
 12.2989 +
 12.2990 +   This command allows the client to determine whether an article exists
 12.2991 +   and, in the second and third forms, what its message-id is, without
 12.2992 +   having to process an arbitrary amount of text.
 12.2993 +
 12.2994 +6.2.4.3.  Examples
 12.2995 +
 12.2996 +   Example of STAT on an existing article (explicitly not using an
 12.2997 +   article number):
 12.2998 +
 12.2999 +      [C] GROUP misc.test
 12.3000 +      [S] 211 1234 3000234 3002322 misc.test
 12.3001 +      [C] STAT
 12.3002 +      [S] 223 3000234 <45223423@example.com>
 12.3003 +
 12.3004 +   Example of STAT on an existing article by message-id:
 12.3005 +
 12.3006 +      [C] STAT <45223423@example.com>
 12.3007 +      [S] 223 0 <45223423@example.com>
 12.3008 +
 12.3009 +   Example of STAT on an article not on the server by message-id:
 12.3010 +
 12.3011 +      [C] STAT <i.am.not.there@example.com>
 12.3012 +      [S] 430 No Such Article Found
 12.3013 +
 12.3014 +   Example of STAT on an article not in the server by number:
 12.3015 +
 12.3016 +      [C] GROUP misc.test
 12.3017 +      [S] 211 1234 3000234 3002322 misc.test
 12.3018 +      [C] STAT 300256
 12.3019 +      [S] 423 No article with that number
 12.3020 +
 12.3021 +
 12.3022 +
 12.3023 +
 12.3024 +Feather                     Standards Track                    [Page 54]
 12.3025 +
 12.3026 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3027 +
 12.3028 +
 12.3029 +   Example of STAT on an article by number when no newsgroup was
 12.3030 +   selected first:
 12.3031 +
 12.3032 +      [Assumes currently selected newsgroup is invalid.]
 12.3033 +      [C] STAT 300256
 12.3034 +      [S] 412 No newsgroup selected
 12.3035 +
 12.3036 +   Example of STAT on an article when the currently selected newsgroup
 12.3037 +   is empty:
 12.3038 +
 12.3039 +      [C] GROUP example.empty.newsgroup
 12.3040 +      [S] 211 0 0 0 example.empty.newsgroup
 12.3041 +      [C] STAT
 12.3042 +      [S] 420 No current article selected
 12.3043 +
 12.3044 +   Example of STAT by message-id on a server that sometimes reports the
 12.3045 +   actual article number:
 12.3046 +
 12.3047 +      [C] GROUP misc.test
 12.3048 +      [S] 211 1234 3000234 3002322 misc.test
 12.3049 +      [C] STAT
 12.3050 +      [S] 223 3000234 <45223423@example.com>
 12.3051 +      [C] STAT <45223423@example.com>
 12.3052 +      [S] 223 0 <45223423@example.com>
 12.3053 +      [C] STAT <45223423@example.com>
 12.3054 +      [S] 223 3000234 <45223423@example.com>
 12.3055 +      [C] GROUP example.empty.newsgroup
 12.3056 +      [S] 211 0 0 0 example.empty.newsgroup
 12.3057 +      [C] STAT <45223423@example.com>
 12.3058 +      [S] 223 0 <45223423@example.com>
 12.3059 +      [C] GROUP alt.crossposts
 12.3060 +      [S] 211 9999 111111 222222 alt.crossposts
 12.3061 +      [C] STAT <45223423@example.com>
 12.3062 +      [S] 223 123456 <45223423@example.com>
 12.3063 +      [C] STAT
 12.3064 +      [S] 223 111111 <23894720@example.com>
 12.3065 +
 12.3066 +   The first STAT command establishes the identity of an article in the
 12.3067 +   group.  The second and third show that the server may, but need not,
 12.3068 +   give the article number when the message-id is specified.  The fourth
 12.3069 +   STAT command shows that zero must be specified if the article isn't
 12.3070 +   in the currently selected newsgroup.  The fifth shows that the
 12.3071 +   number, if provided, must be that relating to the currently selected
 12.3072 +   newsgroup.  The last one shows that the current article number is
 12.3073 +   still not changed by the use of STAT with a message-id even if it
 12.3074 +   returns an article number.
 12.3075 +
 12.3076 +
 12.3077 +
 12.3078 +
 12.3079 +
 12.3080 +Feather                     Standards Track                    [Page 55]
 12.3081 +
 12.3082 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3083 +
 12.3084 +
 12.3085 +6.3.  Article Posting
 12.3086 +
 12.3087 +   Article posting is done in one of two ways: individual article
 12.3088 +   posting from news-reading clients using POST, and article transfer
 12.3089 +   from other news servers using IHAVE.
 12.3090 +
 12.3091 +6.3.1.  POST
 12.3092 +
 12.3093 +6.3.1.1.  Usage
 12.3094 +
 12.3095 +   Indicating capability: POST
 12.3096 +
 12.3097 +   This command MUST NOT be pipelined.
 12.3098 +
 12.3099 +   Syntax
 12.3100 +     POST
 12.3101 +
 12.3102 +   Responses
 12.3103 +
 12.3104 +   Initial responses
 12.3105 +     340    Send article to be posted
 12.3106 +     440    Posting not permitted
 12.3107 +
 12.3108 +   Subsequent responses
 12.3109 +     240    Article received OK
 12.3110 +     441    Posting failed
 12.3111 +
 12.3112 +6.3.1.2.  Description
 12.3113 +
 12.3114 +   If posting is allowed, a 340 response MUST be returned to indicate
 12.3115 +   that the article to be posted should be sent.  If posting is
 12.3116 +   prohibited for some installation-dependent reason, a 440 response
 12.3117 +   MUST be returned.
 12.3118 +
 12.3119 +   If posting is permitted, the article MUST be in the format specified
 12.3120 +   in Section 3.6 and MUST be sent by the client to the server as a
 12.3121 +   multi-line data block (see Section 3.1.1).  Thus a single dot (".")
 12.3122 +   on a line indicates the end of the text, and lines starting with a
 12.3123 +   dot in the original text have that dot doubled during transmission.
 12.3124 +
 12.3125 +   Following the presentation of the termination sequence by the client,
 12.3126 +   the server MUST return a response indicating success or failure of
 12.3127 +   the article transfer.  Note that response codes 340 and 440 are used
 12.3128 +   in direct response to the POST command while 240 and 441 are returned
 12.3129 +   after the article is sent.
 12.3130 +
 12.3131 +
 12.3132 +
 12.3133 +
 12.3134 +
 12.3135 +
 12.3136 +Feather                     Standards Track                    [Page 56]
 12.3137 +
 12.3138 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3139 +
 12.3140 +
 12.3141 +   A response of 240 SHOULD indicate that, barring unforeseen server
 12.3142 +   errors, the posted article will be made available on the server
 12.3143 +   and/or transferred to other servers, as appropriate, possibly
 12.3144 +   following further processing.  In other words, articles not wanted by
 12.3145 +   the server SHOULD be rejected with a 441 response, rather than being
 12.3146 +   accepted and then discarded silently.  However, the client SHOULD NOT
 12.3147 +   assume that the article has been successfully transferred unless it
 12.3148 +   receives an affirmative response from the server and SHOULD NOT
 12.3149 +   assume that it is being made available to other clients without
 12.3150 +   explicitly checking (for example, using the STAT command).
 12.3151 +
 12.3152 +   If the session is interrupted before the response is received, it is
 12.3153 +   possible that an affirmative response was sent but has been lost.
 12.3154 +   Therefore, in any subsequent session, the client SHOULD either check
 12.3155 +   whether the article was successfully posted before resending or
 12.3156 +   ensure that the server will allocate the same message-id to the new
 12.3157 +   attempt (see Appendix A.2).  The latter approach is preferred since
 12.3158 +   the article might not have been made available for reading yet (for
 12.3159 +   example, it may have to go through a moderation process).
 12.3160 +
 12.3161 +6.3.1.3.  Examples
 12.3162 +
 12.3163 +   Example of a successful posting:
 12.3164 +
 12.3165 +      [C] POST
 12.3166 +      [S] 340 Input article; end with <CR-LF>.<CR-LF>
 12.3167 +      [C] From: "Demo User" <nobody@example.net>
 12.3168 +      [C] Newsgroups: misc.test
 12.3169 +      [C] Subject: I am just a test article
 12.3170 +      [C] Organization: An Example Net
 12.3171 +      [C]
 12.3172 +      [C] This is just a test article.
 12.3173 +      [C] .
 12.3174 +      [S] 240 Article received OK
 12.3175 +
 12.3176 +   Example of an unsuccessful posting:
 12.3177 +
 12.3178 +      [C] POST
 12.3179 +      [S] 340 Input article; end with <CR-LF>.<CR-LF>
 12.3180 +      [C] From: "Demo User" <nobody@example.net>
 12.3181 +      [C] Newsgroups: misc.test
 12.3182 +      [C] Subject: I am just a test article
 12.3183 +      [C] Organization: An Example Net
 12.3184 +      [C]
 12.3185 +      [C] This is just a test article.
 12.3186 +      [C] .
 12.3187 +      [S] 441 Posting failed
 12.3188 +
 12.3189 +
 12.3190 +
 12.3191 +
 12.3192 +Feather                     Standards Track                    [Page 57]
 12.3193 +
 12.3194 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3195 +
 12.3196 +
 12.3197 +   Example of an attempt to post when posting is not allowed:
 12.3198 +
 12.3199 +      [Initial connection set-up completed.]
 12.3200 +      [S] 201 NNTP Service Ready, posting prohibited
 12.3201 +      [C] POST
 12.3202 +      [S] 440 Posting not permitted
 12.3203 +
 12.3204 +6.3.2.  IHAVE
 12.3205 +
 12.3206 +6.3.2.1.  Usage
 12.3207 +
 12.3208 +   Indicating capability: IHAVE
 12.3209 +
 12.3210 +   This command MUST NOT be pipelined.
 12.3211 +
 12.3212 +   Syntax
 12.3213 +     IHAVE message-id
 12.3214 +
 12.3215 +   Responses
 12.3216 +
 12.3217 +   Initial responses
 12.3218 +     335    Send article to be transferred
 12.3219 +     435    Article not wanted
 12.3220 +     436    Transfer not possible; try again later
 12.3221 +
 12.3222 +   Subsequent responses
 12.3223 +     235    Article transferred OK
 12.3224 +     436    Transfer failed; try again later
 12.3225 +     437    Transfer rejected; do not retry
 12.3226 +
 12.3227 +   Parameters
 12.3228 +     message-id    Article message-id
 12.3229 +
 12.3230 +6.3.2.2.  Description
 12.3231 +
 12.3232 +   The IHAVE command informs the server that the client has an article
 12.3233 +   with the specified message-id.  If the server desires a copy of that
 12.3234 +   article, a 335 response MUST be returned, instructing the client to
 12.3235 +   send the entire article.  If the server does not want the article
 12.3236 +   (if, for example, the server already has a copy of it), a 435
 12.3237 +   response MUST be returned, indicating that the article is not wanted.
 12.3238 +   Finally, if the article isn't wanted immediately but the client
 12.3239 +   should retry later if possible (if, for example, another client is in
 12.3240 +   the process of sending the same article to the server), a 436
 12.3241 +   response MUST be returned.
 12.3242 +
 12.3243 +
 12.3244 +
 12.3245 +
 12.3246 +
 12.3247 +
 12.3248 +Feather                     Standards Track                    [Page 58]
 12.3249 +
 12.3250 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3251 +
 12.3252 +
 12.3253 +   If transmission of the article is requested, the client MUST send the
 12.3254 +   entire article, including headers and body, to the server as a
 12.3255 +   multi-line data block (see Section 3.1.1).  Thus, a single dot (".")
 12.3256 +   on a line indicates the end of the text, and lines starting with a
 12.3257 +   dot in the original text have that dot doubled during transmission.
 12.3258 +   The server MUST return a 235 response, indicating that the article
 12.3259 +   was successfully transferred; a 436 response, indicating that the
 12.3260 +   transfer failed but should be tried again later; or a 437 response,
 12.3261 +   indicating that the article was rejected.
 12.3262 +
 12.3263 +   This function differs from the POST command in that it is intended
 12.3264 +   for use in transferring already-posted articles between hosts.  It
 12.3265 +   SHOULD NOT be used when the client is a personal news-reading
 12.3266 +   program, since use of this command indicates that the article has
 12.3267 +   already been posted at another site and is simply being forwarded
 12.3268 +   from another host.  However, despite this, the server MAY elect not
 12.3269 +   to post or forward the article if, after further examination of the
 12.3270 +   article, it deems it inappropriate to do so.  Reasons for such
 12.3271 +   subsequent rejection of an article may include problems such as
 12.3272 +   inappropriate newsgroups or distributions, disc space limitations,
 12.3273 +   article lengths, garbled headers, and the like.  These are typically
 12.3274 +   restrictions enforced by the server host's news software and not
 12.3275 +   necessarily by the NNTP server itself.
 12.3276 +
 12.3277 +   The client SHOULD NOT assume that the article has been successfully
 12.3278 +   transferred unless it receives an affirmative response from the
 12.3279 +   server.  A lack of response (such as a dropped network connection or
 12.3280 +   a network timeout) SHOULD be treated the same as a 436 response.
 12.3281 +
 12.3282 +   Because some news server software may not immediately be able to
 12.3283 +   determine whether an article is suitable for posting or forwarding,
 12.3284 +   an NNTP server MAY acknowledge the successful transfer of the article
 12.3285 +   (with a 235 response) but later silently discard it.
 12.3286 +
 12.3287 +
 12.3288 +
 12.3289 +
 12.3290 +
 12.3291 +
 12.3292 +
 12.3293 +
 12.3294 +
 12.3295 +
 12.3296 +
 12.3297 +
 12.3298 +
 12.3299 +
 12.3300 +
 12.3301 +
 12.3302 +
 12.3303 +
 12.3304 +Feather                     Standards Track                    [Page 59]
 12.3305 +
 12.3306 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3307 +
 12.3308 +
 12.3309 +6.3.2.3.  Examples
 12.3310 +
 12.3311 +   Example of successfully sending an article to another site:
 12.3312 +
 12.3313 +      [C] IHAVE <i.am.an.article.you.will.want@example.com>
 12.3314 +      [S] 335 Send it; end with <CR-LF>.<CR-LF>
 12.3315 +      [C] Path: pathost!demo!somewhere!not-for-mail
 12.3316 +      [C] From: "Demo User" <nobody@example.com>
 12.3317 +      [C] Newsgroups: misc.test
 12.3318 +      [C] Subject: I am just a test article
 12.3319 +      [C] Date: 6 Oct 1998 04:38:40 -0500
 12.3320 +      [C] Organization: An Example Com, San Jose, CA
 12.3321 +      [C] Message-ID: <i.am.an.article.you.will.want@example.com>
 12.3322 +      [C]
 12.3323 +      [C] This is just a test article.
 12.3324 +      [C] .
 12.3325 +      [S] 235 Article transferred OK
 12.3326 +
 12.3327 +   Example of sending an article to another site that rejects it.  Note
 12.3328 +   that the message-id in the IHAVE command is not the same as the one
 12.3329 +   in the article headers; while this is bad practice and SHOULD NOT be
 12.3330 +   done, it is not forbidden.
 12.3331 +
 12.3332 +      [C] IHAVE <i.am.an.article.you.will.want@example.com>
 12.3333 +      [S] 335 Send it; end with <CR-LF>.<CR-LF>
 12.3334 +      [C] Path: pathost!demo!somewhere!not-for-mail
 12.3335 +      [C] From: "Demo User" <nobody@example.com>
 12.3336 +      [C] Newsgroups: misc.test
 12.3337 +      [C] Subject: I am just a test article
 12.3338 +      [C] Date: 6 Oct 1998 04:38:40 -0500
 12.3339 +      [C] Organization: An Example Com, San Jose, CA
 12.3340 +      [C] Message-ID: <i.am.an.article.you.have@example.com>
 12.3341 +      [C]
 12.3342 +      [C] This is just a test article.
 12.3343 +      [C] .
 12.3344 +      [S] 437 Article rejected; don't send again
 12.3345 +
 12.3346 +
 12.3347 +
 12.3348 +
 12.3349 +
 12.3350 +
 12.3351 +
 12.3352 +
 12.3353 +
 12.3354 +
 12.3355 +
 12.3356 +
 12.3357 +
 12.3358 +
 12.3359 +
 12.3360 +Feather                     Standards Track                    [Page 60]
 12.3361 +
 12.3362 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3363 +
 12.3364 +
 12.3365 +   Example of sending an article to another site where the transfer
 12.3366 +   fails:
 12.3367 +
 12.3368 +      [C] IHAVE <i.am.an.article.you.will.want@example.com>
 12.3369 +      [S] 335 Send it; end with <CR-LF>.<CR-LF>
 12.3370 +      [C] Path: pathost!demo!somewhere!not-for-mail
 12.3371 +      [C] From: "Demo User" <nobody@example.com>
 12.3372 +      [C] Newsgroups: misc.test
 12.3373 +      [C] Subject: I am just a test article
 12.3374 +      [C] Date: 6 Oct 1998 04:38:40 -0500
 12.3375 +      [C] Organization: An Example Com, San Jose, CA
 12.3376 +      [C] Message-ID: <i.am.an.article.you.will.want@example.com>
 12.3377 +      [C]
 12.3378 +      [C] This is just a test article.
 12.3379 +      [C] .
 12.3380 +      [S] 436 Transfer failed
 12.3381 +
 12.3382 +   Example of sending an article to a site that already has it:
 12.3383 +
 12.3384 +      [C] IHAVE <i.am.an.article.you.have@example.com>
 12.3385 +      [S] 435 Duplicate
 12.3386 +
 12.3387 +   Example of sending an article to a site that requests that the
 12.3388 +   article be tried again later:
 12.3389 +
 12.3390 +      [C] IHAVE <i.am.an.article.you.defer@example.com>
 12.3391 +      [S] 436 Retry later
 12.3392 +
 12.3393 +7.  Information Commands
 12.3394 +
 12.3395 +   This section lists other commands that may be used at any time
 12.3396 +   between the beginning of a session and its termination.  Using these
 12.3397 +   commands does not alter any state information, but the response
 12.3398 +   generated from their use may provide useful information to clients.
 12.3399 +
 12.3400 +7.1.  DATE
 12.3401 +
 12.3402 +7.1.1.  Usage
 12.3403 +
 12.3404 +   Indicating capability: READER
 12.3405 +
 12.3406 +   Syntax
 12.3407 +     DATE
 12.3408 +
 12.3409 +   Responses
 12.3410 +     111 yyyymmddhhmmss    Server date and time
 12.3411 +
 12.3412 +
 12.3413 +
 12.3414 +
 12.3415 +
 12.3416 +Feather                     Standards Track                    [Page 61]
 12.3417 +
 12.3418 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3419 +
 12.3420 +
 12.3421 +   Parameters
 12.3422 +     yyyymmddhhmmss    Current UTC date and time on server
 12.3423 +
 12.3424 +7.1.2.  Description
 12.3425 +
 12.3426 +   This command exists to help clients find out the current Coordinated
 12.3427 +   Universal Time [TF.686-1] from the server's perspective.  This
 12.3428 +   command SHOULD NOT be used as a substitute for NTP [RFC1305] but to
 12.3429 +   provide information that might be useful when using the NEWNEWS
 12.3430 +   command (see Section 7.4).
 12.3431 +
 12.3432 +   The DATE command MUST return a timestamp from the same clock as is
 12.3433 +   used for determining article arrival and group creation times (see
 12.3434 +   Section 6).  This clock SHOULD be monotonic, and adjustments SHOULD
 12.3435 +   be made by running it fast or slow compared to "real" time rather
 12.3436 +   than by making sudden jumps.  A system providing NNTP service SHOULD
 12.3437 +   keep the system clock as accurate as possible, either with NTP or by
 12.3438 +   some other method.
 12.3439 +
 12.3440 +   The server MUST return a 111 response specifying the date and time on
 12.3441 +   the server in the form yyyymmddhhmmss.  This date and time is in
 12.3442 +   Coordinated Universal Time.
 12.3443 +
 12.3444 +7.1.3.  Examples
 12.3445 +
 12.3446 +      [C] DATE
 12.3447 +      [S] 111 19990623135624
 12.3448 +
 12.3449 +7.2.  HELP
 12.3450 +
 12.3451 +7.2.1.  Usage
 12.3452 +
 12.3453 +   This command is mandatory.
 12.3454 +
 12.3455 +   Syntax
 12.3456 +     HELP
 12.3457 +
 12.3458 +   Responses
 12.3459 +     100    Help text follows (multi-line)
 12.3460 +
 12.3461 +7.2.2.  Description
 12.3462 +
 12.3463 +   This command provides a short summary of the commands that are
 12.3464 +   understood by this implementation of the server.  The help text will
 12.3465 +   be presented as a multi-line data block following the 100 response
 12.3466 +   code.
 12.3467 +
 12.3468 +
 12.3469 +
 12.3470 +
 12.3471 +
 12.3472 +Feather                     Standards Track                    [Page 62]
 12.3473 +
 12.3474 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3475 +
 12.3476 +
 12.3477 +   This text is not guaranteed to be in any particular format (but must
 12.3478 +   be UTF-8) and MUST NOT be used by clients as a replacement for the
 12.3479 +   CAPABILITIES command described in Section 5.2.
 12.3480 +
 12.3481 +7.2.3.  Examples
 12.3482 +
 12.3483 +      [C] HELP
 12.3484 +      [S] 100 Help text follows
 12.3485 +      [S] This is some help text.  There is no specific
 12.3486 +      [S] formatting requirement for this test, though
 12.3487 +      [S] it is customary for it to list the valid commands
 12.3488 +      [S] and give a brief definition of what they do.
 12.3489 +      [S] .
 12.3490 +
 12.3491 +7.3.  NEWGROUPS
 12.3492 +
 12.3493 +7.3.1.  Usage
 12.3494 +
 12.3495 +   Indicating capability: READER
 12.3496 +
 12.3497 +   Syntax
 12.3498 +     NEWGROUPS date time [GMT]
 12.3499 +
 12.3500 +   Responses
 12.3501 +     231    List of new newsgroups follows (multi-line)
 12.3502 +
 12.3503 +   Parameters
 12.3504 +     date    Date in yymmdd or yyyymmdd format
 12.3505 +     time    Time in hhmmss format
 12.3506 +
 12.3507 +7.3.2.  Description
 12.3508 +
 12.3509 +   This command returns a list of newsgroups created on the server since
 12.3510 +   the specified date and time.  The results are in the same format as
 12.3511 +   the LIST ACTIVE command (see Section 7.6.3).  However, they MAY
 12.3512 +   include groups not available on the server (and so not returned by
 12.3513 +   LIST ACTIVE) and MAY omit groups for which the creation date is not
 12.3514 +   available.
 12.3515 +
 12.3516 +   The date is specified as 6 or 8 digits in the format [xx]yymmdd,
 12.3517 +   where xx is the first two digits of the year (19-99), yy is the last
 12.3518 +   two digits of the year (00-99), mm is the month (01-12), and dd is
 12.3519 +   the day of the month (01-31).  Clients SHOULD specify all four digits
 12.3520 +   of the year.  If the first two digits of the year are not specified
 12.3521 +   (this is supported only for backward compatibility), the year is to
 12.3522 +   be taken from the current century if yy is smaller than or equal to
 12.3523 +   the current year, and the previous century otherwise.
 12.3524 +
 12.3525 +
 12.3526 +
 12.3527 +
 12.3528 +Feather                     Standards Track                    [Page 63]
 12.3529 +
 12.3530 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3531 +
 12.3532 +
 12.3533 +   The time is specified as 6 digits in the format hhmmss, where hh is
 12.3534 +   the hours in the 24-hour clock (00-23), mm is the minutes (00-59),
 12.3535 +   and ss is the seconds (00-60, to allow for leap seconds).  The token
 12.3536 +   "GMT" specifies that the date and time are given in Coordinated
 12.3537 +   Universal Time [TF.686-1]; if it is omitted, then the date and time
 12.3538 +   are specified in the server's local timezone.  Note that there is no
 12.3539 +   way of using the protocol specified in this document to establish the
 12.3540 +   server's local timezone.
 12.3541 +
 12.3542 +   Note that an empty list is a possible valid response and indicates
 12.3543 +   that there are no new newsgroups since that date-time.
 12.3544 +
 12.3545 +   Clients SHOULD make all queries using Coordinated Universal Time
 12.3546 +   (i.e., by including the "GMT" argument) when possible.
 12.3547 +
 12.3548 +7.3.3.  Examples
 12.3549 +
 12.3550 +   Example where there are new groups:
 12.3551 +
 12.3552 +      [C] NEWGROUPS 19990624 000000 GMT
 12.3553 +      [S] 231 list of new newsgroups follows
 12.3554 +      [S] alt.rfc-writers.recovery 4 1 y
 12.3555 +      [S] tx.natives.recovery 89 56 y
 12.3556 +      [S] .
 12.3557 +
 12.3558 +   Example where there are no new groups:
 12.3559 +
 12.3560 +      [C] NEWGROUPS 19990624 000000 GMT
 12.3561 +      [S] 231 list of new newsgroups follows
 12.3562 +      [S] .
 12.3563 +
 12.3564 +7.4.  NEWNEWS
 12.3565 +
 12.3566 +7.4.1.  Usage
 12.3567 +
 12.3568 +   Indicating capability: NEWNEWS
 12.3569 +
 12.3570 +   Syntax
 12.3571 +     NEWNEWS wildmat date time [GMT]
 12.3572 +
 12.3573 +   Responses
 12.3574 +     230    List of new articles follows (multi-line)
 12.3575 +
 12.3576 +   Parameters
 12.3577 +     wildmat    Newsgroups of interest
 12.3578 +     date       Date in yymmdd or yyyymmdd format
 12.3579 +     time       Time in hhmmss format
 12.3580 +
 12.3581 +
 12.3582 +
 12.3583 +
 12.3584 +Feather                     Standards Track                    [Page 64]
 12.3585 +
 12.3586 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3587 +
 12.3588 +
 12.3589 +7.4.2.  Description
 12.3590 +
 12.3591 +   This command returns a list of message-ids of articles posted or
 12.3592 +   received on the server, in the newsgroups whose names match the
 12.3593 +   wildmat, since the specified date and time.  One message-id is sent
 12.3594 +   on each line; the order of the response has no specific significance
 12.3595 +   and may vary from response to response in the same session.  A
 12.3596 +   message-id MAY appear more than once; if it does, it has the same
 12.3597 +   meaning as if it appeared only once.
 12.3598 +
 12.3599 +   Date and time are in the same format as the NEWGROUPS command (see
 12.3600 +   Section 7.3).
 12.3601 +
 12.3602 +   Note that an empty list is a possible valid response and indicates
 12.3603 +   that there is currently no new news in the relevant groups.
 12.3604 +
 12.3605 +   Clients SHOULD make all queries in Coordinated Universal Time (i.e.,
 12.3606 +   by using the "GMT" argument) when possible.
 12.3607 +
 12.3608 +7.4.3.  Examples
 12.3609 +
 12.3610 +   Example where there are new articles:
 12.3611 +
 12.3612 +      [C] NEWNEWS news.*,sci.* 19990624 000000 GMT
 12.3613 +      [S] 230 list of new articles by message-id follows
 12.3614 +      [S] <i.am.a.new.article@example.com>
 12.3615 +      [S] <i.am.another.new.article@example.com>
 12.3616 +      [S] .
 12.3617 +
 12.3618 +   Example where there are no new articles:
 12.3619 +
 12.3620 +      [C] NEWNEWS alt.* 19990624 000000 GMT
 12.3621 +      [S] 230 list of new articles by message-id follows
 12.3622 +      [S] .
 12.3623 +
 12.3624 +7.5.  Time
 12.3625 +
 12.3626 +   As described in Section 6, each article has an arrival timestamp.
 12.3627 +   Each newsgroup also has a creation timestamp.  These timestamps are
 12.3628 +   used by the NEWNEWS and NEWGROUP commands to construct their
 12.3629 +   responses.
 12.3630 +
 12.3631 +   Clients can ensure that they do not have gaps in lists of articles or
 12.3632 +   groups by using the DATE command in the following manner:
 12.3633 +
 12.3634 +   First session:
 12.3635 +      Issue DATE command and record result.
 12.3636 +      Issue NEWNEWS command using a previously chosen timestamp.
 12.3637 +
 12.3638 +
 12.3639 +
 12.3640 +Feather                     Standards Track                    [Page 65]
 12.3641 +
 12.3642 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3643 +
 12.3644 +
 12.3645 +   Subsequent sessions:
 12.3646 +      Issue DATE command and hold result in temporary storage.
 12.3647 +      Issue NEWNEWS command using timestamp saved from previous session.
 12.3648 +      Overwrite saved timestamp with that currently in temporary
 12.3649 +      storage.
 12.3650 +
 12.3651 +   In order to allow for minor errors, clients MAY want to adjust the
 12.3652 +   timestamp back by two or three minutes before using it in NEWNEWS.
 12.3653 +
 12.3654 +7.5.1.  Examples
 12.3655 +
 12.3656 +   First session:
 12.3657 +
 12.3658 +      [C] DATE
 12.3659 +      [S] 111 20010203112233
 12.3660 +      [C] NEWNEWS local.chat 20001231 235959 GMT
 12.3661 +      [S] 230 list follows
 12.3662 +      [S] <article.1@local.service>
 12.3663 +      [S] <article.2@local.service>
 12.3664 +      [S] <article.3@local.service>
 12.3665 +      [S] .
 12.3666 +
 12.3667 +   Second session (the client has subtracted 3 minutes from the
 12.3668 +   timestamp returned previously):
 12.3669 +
 12.3670 +      [C] DATE
 12.3671 +      [S] 111 20010204003344
 12.3672 +      [C] NEWNEWS local.chat 20010203 111933 GMT
 12.3673 +      [S] 230 list follows
 12.3674 +      [S] <article.3@local.service>
 12.3675 +      [S] <article.4@local.service>
 12.3676 +      [S] <article.5@local.service>
 12.3677 +      [S] .
 12.3678 +
 12.3679 +   Note how <article.3@local.service> arrived in the 3 minute gap and so
 12.3680 +   is listed in both responses.
 12.3681 +
 12.3682 +7.6.  The LIST Commands
 12.3683 +
 12.3684 +   The LIST family of commands all return information that is multi-line
 12.3685 +   and that can, in general, be expected not to change during the
 12.3686 +   session.  Often the information is related to newsgroups, in which
 12.3687 +   case the response has one line per newsgroup and a wildmat MAY be
 12.3688 +   provided to restrict the groups for which information is returned.
 12.3689 +
 12.3690 +   The set of available keywords (including those provided by
 12.3691 +   extensions) is given in the capability list with capability label
 12.3692 +   LIST.
 12.3693 +
 12.3694 +
 12.3695 +
 12.3696 +Feather                     Standards Track                    [Page 66]
 12.3697 +
 12.3698 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3699 +
 12.3700 +
 12.3701 +7.6.1.  LIST
 12.3702 +
 12.3703 +7.6.1.1.  Usage
 12.3704 +
 12.3705 +   Indicating capability: LIST
 12.3706 +
 12.3707 +   Syntax
 12.3708 +     LIST [keyword [wildmat|argument]]
 12.3709 +
 12.3710 +   Responses
 12.3711 +     215    Information follows (multi-line)
 12.3712 +
 12.3713 +   Parameters
 12.3714 +     keyword     Information requested [1]
 12.3715 +     argument    Specific to keyword
 12.3716 +     wildmat     Groups of interest
 12.3717 +
 12.3718 +   [1] If no keyword is provided, it defaults to ACTIVE.
 12.3719 +
 12.3720 +7.6.1.2.  Description
 12.3721 +
 12.3722 +   The LIST command allows the server to provide blocks of information
 12.3723 +   to the client.  This information may be global or may be related to
 12.3724 +   newsgroups; in the latter case, the information may be returned
 12.3725 +   either for all groups or only for those matching a wildmat.  Each
 12.3726 +   block of information is represented by a different keyword.  The
 12.3727 +   command returns the specific information identified by the keyword.
 12.3728 +
 12.3729 +   If the information is available, it is returned as a multi-line data
 12.3730 +   block following the 215 response code.  The format of the information
 12.3731 +   depends on the keyword.  The information MAY be affected by the
 12.3732 +   additional argument, but the format MUST NOT be.
 12.3733 +
 12.3734 +   If the information is based on newsgroups and the optional wildmat
 12.3735 +   argument is specified, the response is limited to only the groups (if
 12.3736 +   any) whose names match the wildmat and for which the information is
 12.3737 +   available.
 12.3738 +
 12.3739 +   Note that an empty list is a possible valid response; for a
 12.3740 +   newsgroup-based keyword, it indicates that there are no groups
 12.3741 +   meeting the above criteria.
 12.3742 +
 12.3743 +   If the keyword is not recognised, or if an argument is specified and
 12.3744 +   the keyword does not expect one, a 501 response code MUST BE
 12.3745 +   returned.  If the keyword is recognised but the server does not
 12.3746 +   maintain the information, a 503 response code MUST BE returned.
 12.3747 +
 12.3748 +
 12.3749 +
 12.3750 +
 12.3751 +
 12.3752 +Feather                     Standards Track                    [Page 67]
 12.3753 +
 12.3754 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3755 +
 12.3756 +
 12.3757 +   The LIST command MUST NOT change the visible state of the server in
 12.3758 +   any way; that is, the behaviour of subsequent commands MUST NOT be
 12.3759 +   affected by whether the LIST command was issued.  For example, it
 12.3760 +   MUST NOT make groups available that otherwise would not have been.
 12.3761 +
 12.3762 +7.6.1.3.  Examples
 12.3763 +
 12.3764 +   Example of LIST with the ACTIVE keyword:
 12.3765 +
 12.3766 +      [C] LIST ACTIVE
 12.3767 +      [S] 215 list of newsgroups follows
 12.3768 +      [S] misc.test 3002322 3000234 y
 12.3769 +      [S] comp.risks 442001 441099 m
 12.3770 +      [S] alt.rfc-writers.recovery 4 1 y
 12.3771 +      [S] tx.natives.recovery 89 56 y
 12.3772 +      [S] tx.natives.recovery.d 11 9 n
 12.3773 +      [S] .
 12.3774 +
 12.3775 +   Example of LIST with no keyword:
 12.3776 +
 12.3777 +      [C] LIST
 12.3778 +      [S] 215 list of newsgroups follows
 12.3779 +      [S] misc.test 3002322 3000234 y
 12.3780 +      [S] comp.risks 442001 441099 m
 12.3781 +      [S] alt.rfc-writers.recovery 4 1 y
 12.3782 +      [S] tx.natives.recovery 89 56 y
 12.3783 +      [S] tx.natives.recovery.d 11 9 n
 12.3784 +      [S] .
 12.3785 +
 12.3786 +   The output is identical to that of the previous example.
 12.3787 +
 12.3788 +   Example of LIST on a newsgroup-based keyword with and without
 12.3789 +   wildmat:
 12.3790 +
 12.3791 +      [C] LIST ACTIVE.TIMES
 12.3792 +      [S] 215 information follows
 12.3793 +      [S] misc.test 930445408 <creatme@isc.org>
 12.3794 +      [S] alt.rfc-writers.recovery 930562309 <m@example.com>
 12.3795 +      [S] tx.natives.recovery 930678923 <sob@academ.com>
 12.3796 +      [S] .
 12.3797 +      [C] LIST ACTIVE.TIMES tx.*
 12.3798 +      [S] 215 information follows
 12.3799 +      [S] tx.natives.recovery 930678923 <sob@academ.com>
 12.3800 +      [S] .
 12.3801 +
 12.3802 +
 12.3803 +
 12.3804 +
 12.3805 +
 12.3806 +
 12.3807 +
 12.3808 +Feather                     Standards Track                    [Page 68]
 12.3809 +
 12.3810 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3811 +
 12.3812 +
 12.3813 +   Example of LIST returning an error where the keyword is recognized
 12.3814 +   but the software does not maintain this information:
 12.3815 +
 12.3816 +      [C] CAPABILITIES
 12.3817 +      [S] 101 Capability list:
 12.3818 +      [S] VERSION 2
 12.3819 +      [S] READER
 12.3820 +      [S] LIST ACTIVE NEWSGROUPS ACTIVE.TIMES XTRA.DATA
 12.3821 +      [S] .
 12.3822 +      [C] LIST XTRA.DATA
 12.3823 +      [S] 503 Data item not stored
 12.3824 +
 12.3825 +   Example of LIST where the keyword is not recognised:
 12.3826 +
 12.3827 +      [C] CAPABILITIES
 12.3828 +      [S] 101 Capability list:
 12.3829 +      [S] VERSION 2
 12.3830 +      [S] READER
 12.3831 +      [S] LIST ACTIVE NEWSGROUPS ACTIVE.TIMES XTRA.DATA
 12.3832 +      [S] .
 12.3833 +      [C] LIST DISTRIB.PATS
 12.3834 +      [S] 501 Syntax Error
 12.3835 +
 12.3836 +7.6.2.  Standard LIST Keywords
 12.3837 +
 12.3838 +   This specification defines the following LIST keywords:
 12.3839 +
 12.3840 +   +--------------+---------------+------------------------------------+
 12.3841 +   | Keyword      | Definition    | Status                             |
 12.3842 +   +--------------+---------------+------------------------------------+
 12.3843 +   | ACTIVE       | Section 7.6.3 | Mandatory if the READER capability |
 12.3844 +   |              |               | is advertised                      |
 12.3845 +   |              |               |                                    |
 12.3846 +   | ACTIVE.TIMES | Section 7.6.4 | Optional                           |
 12.3847 +   |              |               |                                    |
 12.3848 +   | DISTRIB.PATS | Section 7.6.5 | Optional                           |
 12.3849 +   |              |               |                                    |
 12.3850 +   | HEADERS      | Section 8.6   | Mandatory if the HDR capability is |
 12.3851 +   |              |               | advertised                         |
 12.3852 +   |              |               |                                    |
 12.3853 +   | NEWSGROUPS   | Section 7.6.6 | Mandatory if the READER capability |
 12.3854 +   |              |               | is advertised                      |
 12.3855 +   |              |               |                                    |
 12.3856 +   | OVERVIEW.FMT | Section 8.4   | Mandatory if the OVER capability   |
 12.3857 +   |              |               | is advertised                      |
 12.3858 +   +--------------+---------------+------------------------------------+
 12.3859 +
 12.3860 +
 12.3861 +
 12.3862 +
 12.3863 +
 12.3864 +Feather                     Standards Track                    [Page 69]
 12.3865 +
 12.3866 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3867 +
 12.3868 +
 12.3869 +   Where one of these LIST keywords is supported by a server, it MUST
 12.3870 +   have the meaning given in the relevant sub-section.
 12.3871 +
 12.3872 +7.6.3.  LIST ACTIVE
 12.3873 +
 12.3874 +   This keyword MUST be supported by servers advertising the READER
 12.3875 +   capability.
 12.3876 +
 12.3877 +   LIST ACTIVE returns a list of valid newsgroups and associated
 12.3878 +   information.  If no wildmat is specified, the server MUST include
 12.3879 +   every group that the client is permitted to select with the GROUP
 12.3880 +   command (Section 6.1.1).  Each line of this list consists of four
 12.3881 +   fields separated from each other by one or more spaces:
 12.3882 +
 12.3883 +   o  The name of the newsgroup.
 12.3884 +   o  The reported high water mark for the group.
 12.3885 +   o  The reported low water mark for the group.
 12.3886 +   o  The current status of the group on this server.
 12.3887 +
 12.3888 +   The reported high and low water marks are as described in the GROUP
 12.3889 +   command (see Section 6.1.1), but note that they are in the opposite
 12.3890 +   order to the 211 response to that command.
 12.3891 +
 12.3892 +   The status field is typically one of the following:
 12.3893 +
 12.3894 +   "y" Posting is permitted.
 12.3895 +
 12.3896 +   "n" Posting is not permitted.
 12.3897 +
 12.3898 +   "m" Postings will be forwarded to the newsgroup moderator.
 12.3899 +
 12.3900 +   The server SHOULD use these values when these meanings are required
 12.3901 +   and MUST NOT use them with any other meaning.  Other values for the
 12.3902 +   status may exist; the definition of these other values and the
 12.3903 +   circumstances under which they are returned may be specified in an
 12.3904 +   extension or may be private to the server.  A client SHOULD treat an
 12.3905 +   unrecognized status as giving no information.
 12.3906 +
 12.3907 +   The status of a newsgroup only indicates how posts to that newsgroup
 12.3908 +   are normally processed and is not necessarily customised to the
 12.3909 +   specific client.  For example, if the current client is forbidden
 12.3910 +   from posting, then this will apply equally to groups with status "y".
 12.3911 +   Conversely, a client with special privileges (not defined by this
 12.3912 +   specification) might be able to post to a group with status "n".
 12.3913 +
 12.3914 +
 12.3915 +
 12.3916 +
 12.3917 +
 12.3918 +
 12.3919 +
 12.3920 +Feather                     Standards Track                    [Page 70]
 12.3921 +
 12.3922 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3923 +
 12.3924 +
 12.3925 +   For example:
 12.3926 +
 12.3927 +      [C] LIST ACTIVE
 12.3928 +      [S] 215 list of newsgroups follows
 12.3929 +      [S] misc.test 3002322 3000234 y
 12.3930 +      [S] comp.risks 442001 441099 m
 12.3931 +      [S] alt.rfc-writers.recovery 4 1 y
 12.3932 +      [S] tx.natives.recovery 89 56 y
 12.3933 +      [S] tx.natives.recovery.d 11 9 n
 12.3934 +      [S] .
 12.3935 +
 12.3936 +   or, on an implementation that includes leading zeroes:
 12.3937 +
 12.3938 +      [C] LIST ACTIVE
 12.3939 +      [S] 215 list of newsgroups follows
 12.3940 +      [S] misc.test 0003002322 0003000234 y
 12.3941 +      [S] comp.risks 0000442001 0000441099 m
 12.3942 +      [S] alt.rfc-writers.recovery 0000000004 0000000001 y
 12.3943 +      [S] tx.natives.recovery 0000000089 0000000056 y
 12.3944 +      [S] tx.natives.recovery.d 0000000011 0000000009 n
 12.3945 +      [S] .
 12.3946 +
 12.3947 +   The information is newsgroup based, and a wildmat MAY be specified,
 12.3948 +   in which case the response is limited to only the groups (if any)
 12.3949 +   whose names match the wildmat.  For example:
 12.3950 +
 12.3951 +      [C] LIST ACTIVE *.recovery
 12.3952 +      [S] 215 list of newsgroups follows
 12.3953 +      [S] alt.rfc-writers.recovery 4 1 y
 12.3954 +      [S] tx.natives.recovery 89 56 y
 12.3955 +      [S] .
 12.3956 +
 12.3957 +7.6.4.  LIST ACTIVE.TIMES
 12.3958 +
 12.3959 +   This keyword is optional.
 12.3960 +
 12.3961 +   The active.times list is maintained by some NNTP servers to contain
 12.3962 +   information about who created a particular newsgroup and when.  Each
 12.3963 +   line of this list consists of three fields separated from each other
 12.3964 +   by one or more spaces.  The first field is the name of the newsgroup.
 12.3965 +   The second is the time when this group was created on this news
 12.3966 +   server, measured in seconds since the start of January 1, 1970.  The
 12.3967 +   third is plain text intended to describe the entity that created the
 12.3968 +   newsgroup; it is often a mailbox as defined in RFC 2822 [RFC2822].
 12.3969 +   For example:
 12.3970 +
 12.3971 +
 12.3972 +
 12.3973 +
 12.3974 +
 12.3975 +
 12.3976 +Feather                     Standards Track                    [Page 71]
 12.3977 +
 12.3978 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.3979 +
 12.3980 +
 12.3981 +      [C] LIST ACTIVE.TIMES
 12.3982 +      [S] 215 information follows
 12.3983 +      [S] misc.test 930445408 <creatme@isc.org>
 12.3984 +      [S] alt.rfc-writers.recovery 930562309 <m@example.com>
 12.3985 +      [S] tx.natives.recovery 930678923 <sob@academ.com>
 12.3986 +      [S] .
 12.3987 +
 12.3988 +   The list MAY omit newsgroups for which the information is unavailable
 12.3989 +   and MAY include groups not available on the server; in particular, it
 12.3990 +   MAY omit all groups created before the date and time of the oldest
 12.3991 +   entry.  The client MUST NOT assume that the list is complete or that
 12.3992 +   it matches the list returned by the LIST ACTIVE command
 12.3993 +   (Section 7.6.3).  The NEWGROUPS command (Section 7.3) may provide a
 12.3994 +   better way to access this information, and the results of the two
 12.3995 +   commands SHOULD be consistent except that, if the latter is invoked
 12.3996 +   with a date and time earlier than the oldest entry in active.times
 12.3997 +   list, its result may include extra groups.
 12.3998 +
 12.3999 +   The information is newsgroup based, and a wildmat MAY be specified,
 12.4000 +   in which case the response is limited to only the groups (if any)
 12.4001 +   whose names match the wildmat.
 12.4002 +
 12.4003 +7.6.5.  LIST DISTRIB.PATS
 12.4004 +
 12.4005 +   This keyword is optional.
 12.4006 +
 12.4007 +   The distrib.pats list is maintained by some NNTP servers to assist
 12.4008 +   clients to choose a value for the content of the Distribution header
 12.4009 +   of a news article being posted.  Each line of this list consists of
 12.4010 +   three fields separated from each other by a colon (":").  The first
 12.4011 +   field is a weight, the second field is a wildmat (which may be a
 12.4012 +   simple newsgroup name), and the third field is a value for the
 12.4013 +   Distribution header content.  For example:
 12.4014 +
 12.4015 +      [C] LIST DISTRIB.PATS
 12.4016 +      [S] 215 information follows
 12.4017 +      [S] 10:local.*:local
 12.4018 +      [S] 5:*:world
 12.4019 +      [S] 20:local.here.*:thissite
 12.4020 +      [S] .
 12.4021 +
 12.4022 +   The client MAY use this information to construct an appropriate
 12.4023 +   Distribution header given the name of a newsgroup.  To do so, it
 12.4024 +   should determine the lines whose second field matches the newsgroup
 12.4025 +   name, select from among them the line with the highest weight (with 0
 12.4026 +   being the lowest), and use the value of the third field to construct
 12.4027 +   the Distribution header.
 12.4028 +
 12.4029 +
 12.4030 +
 12.4031 +
 12.4032 +Feather                     Standards Track                    [Page 72]
 12.4033 +
 12.4034 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4035 +
 12.4036 +
 12.4037 +   The information is not newsgroup based, and an argument MUST NOT be
 12.4038 +   specified.
 12.4039 +
 12.4040 +7.6.6.  LIST NEWSGROUPS
 12.4041 +
 12.4042 +   This keyword MUST be supported by servers advertising the READER
 12.4043 +   capability.
 12.4044 +
 12.4045 +   The newsgroups list is maintained by NNTP servers to contain the name
 12.4046 +   of each newsgroup that is available on the server and a short
 12.4047 +   description about the purpose of the group.  Each line of this list
 12.4048 +   consists of two fields separated from each other by one or more space
 12.4049 +   or TAB characters (the usual practice is a single TAB).  The first
 12.4050 +   field is the name of the newsgroup, and the second is a short
 12.4051 +   description of the group.  For example:
 12.4052 +
 12.4053 +      [C] LIST NEWSGROUPS
 12.4054 +      [S] 215 information follows
 12.4055 +      [S] misc.test General Usenet testing
 12.4056 +      [S] alt.rfc-writers.recovery RFC Writers Recovery
 12.4057 +      [S] tx.natives.recovery Texas Natives Recovery
 12.4058 +      [S] .
 12.4059 +
 12.4060 +   The list MAY omit newsgroups for which the information is unavailable
 12.4061 +   and MAY include groups not available on the server.  The client MUST
 12.4062 +   NOT assume that the list is complete or that it matches the list
 12.4063 +   returned by LIST ACTIVE.
 12.4064 +
 12.4065 +   The description SHOULD be in UTF-8.  However, servers often obtain
 12.4066 +   the information from external sources.  These sources may have used
 12.4067 +   different encodings (ones that use octets in the range 128 to 255 in
 12.4068 +   some other manner) and, in that case, the server MAY pass it on
 12.4069 +   unchanged.  Therefore, clients MUST be prepared to receive such
 12.4070 +   descriptions.
 12.4071 +
 12.4072 +   The information is newsgroup based, and a wildmat MAY be specified,
 12.4073 +   in which case the response is limited to only the groups (if any)
 12.4074 +   whose names match the wildmat.
 12.4075 +
 12.4076 +8.  Article Field Access Commands
 12.4077 +
 12.4078 +   This section lists commands that may be used to access specific
 12.4079 +   article fields; that is, headers of articles and metadata about
 12.4080 +   articles.  These commands typically fetch data from an "overview
 12.4081 +   database", which is a database of headers extracted from incoming
 12.4082 +   articles plus metadata determined as the article arrives.  Only
 12.4083 +   certain fields are included in the database.
 12.4084 +
 12.4085 +
 12.4086 +
 12.4087 +
 12.4088 +Feather                     Standards Track                    [Page 73]
 12.4089 +
 12.4090 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4091 +
 12.4092 +
 12.4093 +   This section is based on the Overview/NOV database [ROBE1995]
 12.4094 +   developed by Geoff Collyer.
 12.4095 +
 12.4096 +8.1.  Article Metadata
 12.4097 +
 12.4098 +   Article "metadata" is data about articles that does not occur within
 12.4099 +   the article itself.  Each metadata item has a name that MUST begin
 12.4100 +   with a colon (and that MUST NOT contain a colon elsewhere within it).
 12.4101 +   As with header names, metadata item names are not case sensitive.
 12.4102 +
 12.4103 +   When generating a metadata item, the server MUST compute it for
 12.4104 +   itself and MUST NOT trust any related value provided in the article.
 12.4105 +   (In particular, a Lines or Bytes header in the article MUST NOT be
 12.4106 +   assumed to specify the correct number of lines or bytes in the
 12.4107 +   article.)  If the server has access to several non-identical copies
 12.4108 +   of an article, the value returned MUST be correct for any copy of
 12.4109 +   that article retrieved during the same session.
 12.4110 +
 12.4111 +   This specification defines two metadata items: ":bytes" and ":lines".
 12.4112 +   Other metadata items may be defined by extensions.  The names of
 12.4113 +   metadata items defined by registered extensions MUST NOT begin with
 12.4114 +   ":x-".  To avoid the risk of a clash with a future registered
 12.4115 +   extension, the names of metadata items defined by private extensions
 12.4116 +   SHOULD begin with ":x-".
 12.4117 +
 12.4118 +8.1.1.  The :bytes Metadata Item
 12.4119 +
 12.4120 +   The :bytes metadata item for an article is a decimal integer.  It
 12.4121 +   SHOULD equal the number of octets in the entire article: headers,
 12.4122 +   body, and separating empty line (counting a CRLF pair as two octets,
 12.4123 +   and excluding both the "." CRLF terminating the response and any "."
 12.4124 +   added for "dot-stuffing" purposes).
 12.4125 +
 12.4126 +   Note to client implementers: some existing servers return a value
 12.4127 +   different from that above.  The commonest reasons for this are as
 12.4128 +   follows:
 12.4129 +
 12.4130 +   o  Counting a CRLF pair as one octet.
 12.4131 +
 12.4132 +   o  Including the "." character used for dot-stuffing in the number.
 12.4133 +
 12.4134 +   o  Including the terminating "." CRLF in the number.
 12.4135 +
 12.4136 +   o  Using one copy of an article for counting the octets but then
 12.4137 +      returning another one that differs in some (permitted) manner.
 12.4138 +
 12.4139 +   Implementations should be prepared for such variation and MUST NOT
 12.4140 +   rely on the value being accurate.
 12.4141 +
 12.4142 +
 12.4143 +
 12.4144 +Feather                     Standards Track                    [Page 74]
 12.4145 +
 12.4146 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4147 +
 12.4148 +
 12.4149 +8.1.2.  The :lines Metadata Item
 12.4150 +
 12.4151 +   The :lines metadata item for an article is a decimal integer.  It
 12.4152 +   MUST equal the number of lines in the article body (excluding the
 12.4153 +   empty line separating headers and body).  Equivalently, it is two
 12.4154 +   less than the number of CRLF pairs that the BODY command would return
 12.4155 +   for that article (the extra two are those following the response code
 12.4156 +   and the termination octet).
 12.4157 +
 12.4158 +8.2.  Database Consistency
 12.4159 +
 12.4160 +   The information stored in the overview database may change over time.
 12.4161 +   If the database records the content or absence of a given field (that
 12.4162 +   is, a header or metadata item) for all articles, it is said to be
 12.4163 +   "consistent" for that field.  If it records the content of a header
 12.4164 +   for some articles but not for others that nevertheless included that
 12.4165 +   header, or if it records a metadata item for some articles but not
 12.4166 +   for others to which that item applies, it is said to be
 12.4167 +   "inconsistent" for that field.
 12.4168 +
 12.4169 +   The LIST OVERVIEW.FMT command SHOULD list all the fields for which
 12.4170 +   the database is consistent at that moment.  It MAY omit such fields
 12.4171 +   (for example, if it is not known whether the database is consistent
 12.4172 +   or inconsistent).  It MUST NOT include fields for which the database
 12.4173 +   is inconsistent or that are not stored in the database.  Therefore,
 12.4174 +   if a header appears in the LIST OVERVIEW.FMT output but not in the
 12.4175 +   OVER output for a given article, that header does not appear in the
 12.4176 +   article (similarly for metadata items).
 12.4177 +
 12.4178 +   These rules assume that the fields being stored in the database
 12.4179 +   remain constant for long periods of time, and therefore the database
 12.4180 +   will be consistent.  When the set of fields to be stored is changed,
 12.4181 +   it will be inconsistent until either the database is rebuilt or the
 12.4182 +   only articles remaining are those received since the change.
 12.4183 +   Therefore, the output from LIST OVERVIEW.FMT needs to be altered
 12.4184 +   twice.  Firstly, before any fields stop being stored they MUST be
 12.4185 +   removed from the output; then, when the database is once more known
 12.4186 +   to be consistent, the new fields SHOULD be added to the output.
 12.4187 +
 12.4188 +   If the HDR command uses the overview database rather than taking
 12.4189 +   information directly from the articles, the same issues of
 12.4190 +   consistency and inconsistency apply, and the LIST HEADERS command
 12.4191 +   SHOULD take the same approach as the LIST OVERVIEW.FMT command in
 12.4192 +   resolving them.
 12.4193 +
 12.4194 +
 12.4195 +
 12.4196 +
 12.4197 +
 12.4198 +
 12.4199 +
 12.4200 +Feather                     Standards Track                    [Page 75]
 12.4201 +
 12.4202 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4203 +
 12.4204 +
 12.4205 +8.3.  OVER
 12.4206 +
 12.4207 +8.3.1.  Usage
 12.4208 +
 12.4209 +   Indicating capability: OVER
 12.4210 +
 12.4211 +   Syntax
 12.4212 +     OVER message-id
 12.4213 +     OVER range
 12.4214 +     OVER
 12.4215 +
 12.4216 +   Responses
 12.4217 +
 12.4218 +   First form (message-id specified)
 12.4219 +     224    Overview information follows (multi-line)
 12.4220 +     430    No article with that message-id
 12.4221 +
 12.4222 +   Second form (range specified)
 12.4223 +     224    Overview information follows (multi-line)
 12.4224 +     412    No newsgroup selected
 12.4225 +     423    No articles in that range
 12.4226 +
 12.4227 +   Third form (current article number used)
 12.4228 +     224    Overview information follows (multi-line)
 12.4229 +     412    No newsgroup selected
 12.4230 +     420    Current article number is invalid
 12.4231 +
 12.4232 +   Parameters
 12.4233 +     range         Number(s) of articles
 12.4234 +     message-id    Message-id of article
 12.4235 +
 12.4236 +8.3.2.  Description
 12.4237 +
 12.4238 +   The OVER command returns the contents of all the fields in the
 12.4239 +   database for an article specified by message-id, or from a specified
 12.4240 +   article or range of articles in the currently selected newsgroup.
 12.4241 +
 12.4242 +   The message-id argument indicates a specific article.  The range
 12.4243 +   argument may be any of the following:
 12.4244 +
 12.4245 +   o  An article number.
 12.4246 +
 12.4247 +   o  An article number followed by a dash to indicate all following.
 12.4248 +
 12.4249 +   o  An article number followed by a dash followed by another article
 12.4250 +      number.
 12.4251 +
 12.4252 +   If neither is specified, the current article number is used.
 12.4253 +
 12.4254 +
 12.4255 +
 12.4256 +Feather                     Standards Track                    [Page 76]
 12.4257 +
 12.4258 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4259 +
 12.4260 +
 12.4261 +   Support for the first (message-id) form is optional.  If it is
 12.4262 +   supported, the OVER capability line MUST include the argument
 12.4263 +   "MSGID".  Otherwise, the capability line MUST NOT include this
 12.4264 +   argument, and the OVER command MUST return the generic response code
 12.4265 +   503 when this form is used.
 12.4266 +
 12.4267 +   If the information is available, it is returned as a multi-line data
 12.4268 +   block following the 224 response code and contains one line per
 12.4269 +   article, sorted in numerical order of article number.  (Note that
 12.4270 +   unless the argument is a range including a dash, there will be
 12.4271 +   exactly one line in the data block.)  Each line consists of a number
 12.4272 +   of fields separated by a TAB.  A field may be empty (in which case
 12.4273 +   there will be two adjacent TABs), and a sequence of trailing TABs may
 12.4274 +   be omitted.
 12.4275 +
 12.4276 +   The first 8 fields MUST be the following, in order:
 12.4277 +
 12.4278 +      "0" or article number (see below)
 12.4279 +      Subject header content
 12.4280 +      From header content
 12.4281 +      Date header content
 12.4282 +      Message-ID header content
 12.4283 +      References header content
 12.4284 +      :bytes metadata item
 12.4285 +      :lines metadata item
 12.4286 +
 12.4287 +   If the article is specified by message-id (the first form of the
 12.4288 +   command), the article number MUST be replaced with zero, except that
 12.4289 +   if there is a currently selected newsgroup and the article is present
 12.4290 +   in that group, the server MAY use the article's number in that group.
 12.4291 +   (See the ARTICLE command (Section 6.2.1) and STAT examples
 12.4292 +   (Section 6.2.4.3) for more details.)  In the other two forms of the
 12.4293 +   command, the article number MUST be returned.
 12.4294 +
 12.4295 +   Any subsequent fields are the contents of the other headers and
 12.4296 +   metadata held in the database.
 12.4297 +
 12.4298 +   For the five mandatory headers, the content of each field MUST be
 12.4299 +   based on the content of the header (that is, with the header name and
 12.4300 +   following colon and space removed).  If the article does not contain
 12.4301 +   that header, or if the content is empty, the field MUST be empty.
 12.4302 +   For the two mandatory metadata items, the content of the field MUST
 12.4303 +   be just the value, with no other text.
 12.4304 +
 12.4305 +   For all subsequent fields that contain headers, the content MUST be
 12.4306 +   the entire header line other than the trailing CRLF.  For all
 12.4307 +   subsequent fields that contain metadata, the field consists of the
 12.4308 +   metadata name, a single space, and then the value.
 12.4309 +
 12.4310 +
 12.4311 +
 12.4312 +Feather                     Standards Track                    [Page 77]
 12.4313 +
 12.4314 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4315 +
 12.4316 +
 12.4317 +   For all fields, the value is processed by first removing all CRLF
 12.4318 +   pairs (that is, undoing any folding and removing the terminating
 12.4319 +   CRLF) and then replacing each TAB with a single space.  If there is
 12.4320 +   no such header in the article, no such metadata item, or no header or
 12.4321 +   item stored in the database for that article, the corresponding field
 12.4322 +   MUST be empty.
 12.4323 +
 12.4324 +   Note that, after unfolding, the characters NUL, LF, and CR cannot
 12.4325 +   occur in the header of an article offered by a conformant server.
 12.4326 +   Nevertheless, servers SHOULD check for these characters and replace
 12.4327 +   each one by a single space (so that, for example, CR LF LF TAB will
 12.4328 +   become two spaces, since the CR and first LF will be removed by the
 12.4329 +   unfolding process).  This will encourage robustness in the face of
 12.4330 +   non-conforming data; it is also possible that future versions of this
 12.4331 +   specification could permit these characters to appear in articles.
 12.4332 +
 12.4333 +   The server SHOULD NOT produce output for articles that no longer
 12.4334 +   exist.
 12.4335 +
 12.4336 +   If the argument is a message-id and no such article exists, a 430
 12.4337 +   response MUST be returned.  If the argument is a range or is omitted
 12.4338 +   and the currently selected newsgroup is invalid, a 412 response MUST
 12.4339 +   be returned.  If the argument is a range and no articles in that
 12.4340 +   number range exist in the currently selected newsgroup, including the
 12.4341 +   case where the second number is less than the first one, a 423
 12.4342 +   response MUST be returned.  If the argument is omitted and the
 12.4343 +   current article number is invalid, a 420 response MUST be returned.
 12.4344 +
 12.4345 +8.3.3.  Examples
 12.4346 +
 12.4347 +   In the first four examples, TAB has been replaced by vertical bar and
 12.4348 +   some lines have been folded for readability.
 12.4349 +
 12.4350 +   Example of a successful retrieval of overview information for an
 12.4351 +   article (explicitly not using an article number):
 12.4352 +
 12.4353 +      [C] GROUP misc.test
 12.4354 +      [S] 211 1234 3000234 3002322 misc.test
 12.4355 +      [C] OVER
 12.4356 +      [S] 224 Overview information follows
 12.4357 +      [S] 3000234|I am just a test article|"Demo User"
 12.4358 +          <nobody@example.com>|6 Oct 1998 04:38:40 -0500|
 12.4359 +          <45223423@example.com>|<45454@example.net>|1234|
 12.4360 +          17|Xref: news.example.com misc.test:3000363
 12.4361 +      [S] .
 12.4362 +
 12.4363 +
 12.4364 +
 12.4365 +
 12.4366 +
 12.4367 +
 12.4368 +Feather                     Standards Track                    [Page 78]
 12.4369 +
 12.4370 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4371 +
 12.4372 +
 12.4373 +   Example of a successful retrieval of overview information for an
 12.4374 +   article by message-id:
 12.4375 +
 12.4376 +      [C] CAPABILITIES
 12.4377 +      [S] 101 Capability list:
 12.4378 +      [S] VERSION 2
 12.4379 +      [S] READER
 12.4380 +      [S] OVER MSGID
 12.4381 +      [S] LIST ACTIVE NEWSGROUPS OVERVIEW.FMT
 12.4382 +      [S] .
 12.4383 +      [C] OVER <45223423@example.com>
 12.4384 +      [S] 224 Overview information follows
 12.4385 +      [S] 0|I am just a test article|"Demo User"
 12.4386 +          <nobody@example.com>|6 Oct 1998 04:38:40 -0500|
 12.4387 +          <45223423@example.com>|<45454@example.net>|1234|
 12.4388 +          17|Xref: news.example.com misc.test:3000363
 12.4389 +      [S] .
 12.4390 +
 12.4391 +   Note that the article number has been replaced by "0".
 12.4392 +
 12.4393 +   Example of the same commands on a system that does not implement
 12.4394 +   retrieval by message-id:
 12.4395 +
 12.4396 +      [C] CAPABILITIES
 12.4397 +      [S] 101 Capability list:
 12.4398 +      [S] VERSION 2
 12.4399 +      [S] READER
 12.4400 +      [S] OVER
 12.4401 +      [S] LIST ACTIVE NEWSGROUPS OVERVIEW.FMT
 12.4402 +      [S] .
 12.4403 +      [C] OVER <45223423@example.com>
 12.4404 +      [S] 503 Overview by message-id unsupported
 12.4405 +
 12.4406 +
 12.4407 +
 12.4408 +
 12.4409 +
 12.4410 +
 12.4411 +
 12.4412 +
 12.4413 +
 12.4414 +
 12.4415 +
 12.4416 +
 12.4417 +
 12.4418 +
 12.4419 +
 12.4420 +
 12.4421 +
 12.4422 +
 12.4423 +
 12.4424 +Feather                     Standards Track                    [Page 79]
 12.4425 +
 12.4426 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4427 +
 12.4428 +
 12.4429 +   Example of a successful retrieval of overview information for a range
 12.4430 +   of articles:
 12.4431 +
 12.4432 +      [C] GROUP misc.test
 12.4433 +      [S] 211 1234 3000234 3002322 misc.test
 12.4434 +      [C] OVER 3000234-3000240
 12.4435 +      [S] 224 Overview information follows
 12.4436 +      [S] 3000234|I am just a test article|"Demo User"
 12.4437 +          <nobody@example.com>|6 Oct 1998 04:38:40 -0500|
 12.4438 +          <45223423@example.com>|<45454@example.net>|1234|
 12.4439 +          17|Xref: news.example.com misc.test:3000363
 12.4440 +      [S] 3000235|Another test article|nobody@nowhere.to
 12.4441 +          (Demo User)|6 Oct 1998 04:38:45 -0500|<45223425@to.to>||
 12.4442 +          4818|37||Distribution: fi
 12.4443 +      [S] 3000238|Re: I am just a test article|somebody@elsewhere.to|
 12.4444 +          7 Oct 1998 11:38:40 +1200|<kfwer3v@elsewhere.to>|
 12.4445 +          <45223423@to.to>|9234|51
 12.4446 +      [S] .
 12.4447 +
 12.4448 +   Note the missing "References" and Xref headers in the second line,
 12.4449 +   the missing trailing fields in the first and last lines, and that
 12.4450 +   there are only results for those articles that still exist.
 12.4451 +
 12.4452 +   Example of an unsuccessful retrieval of overview information on an
 12.4453 +   article by number:
 12.4454 +
 12.4455 +      [C] GROUP misc.test
 12.4456 +      [S] 211 1234 3000234 3002322 misc.test
 12.4457 +      [C] OVER 300256
 12.4458 +      [S] 423 No such article in this group
 12.4459 +
 12.4460 +   Example of an invalid range:
 12.4461 +
 12.4462 +      [C] GROUP misc.test
 12.4463 +      [S] 211 1234 3000234 3002322 misc.test
 12.4464 +      [C] OVER 3000444-3000222
 12.4465 +      [S] 423 Empty range
 12.4466 +
 12.4467 +   Example of an unsuccessful retrieval of overview information by
 12.4468 +   number because no newsgroup was selected first:
 12.4469 +
 12.4470 +      [Assumes currently selected newsgroup is invalid.]
 12.4471 +      [C] OVER
 12.4472 +      [S] 412 No newsgroup selected
 12.4473 +
 12.4474 +
 12.4475 +
 12.4476 +
 12.4477 +
 12.4478 +
 12.4479 +
 12.4480 +Feather                     Standards Track                    [Page 80]
 12.4481 +
 12.4482 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4483 +
 12.4484 +
 12.4485 +   Example of an attempt to retrieve information when the currently
 12.4486 +   selected newsgroup is empty:
 12.4487 +
 12.4488 +      [C] GROUP example.empty.newsgroup
 12.4489 +      [S] 211 0 0 0 example.empty.newsgroup
 12.4490 +      [C] OVER
 12.4491 +      [S] 420 No current article selected
 12.4492 +
 12.4493 +8.4.  LIST OVERVIEW.FMT
 12.4494 +
 12.4495 +8.4.1.  Usage
 12.4496 +
 12.4497 +   Indicating capability: OVER
 12.4498 +
 12.4499 +   Syntax
 12.4500 +     LIST OVERVIEW.FMT
 12.4501 +
 12.4502 +   Responses
 12.4503 +     215    Information follows (multi-line)
 12.4504 +
 12.4505 +8.4.2.  Description
 12.4506 +
 12.4507 +   See Section 7.6.1 for general requirements of the LIST command.
 12.4508 +
 12.4509 +   The LIST OVERVIEW.FMT command returns a description of the fields in
 12.4510 +   the database for which it is consistent (as described above).  The
 12.4511 +   information is returned as a multi-line data block following the 215
 12.4512 +   response code.  The information contains one line per field in the
 12.4513 +   order in which they are returned by the OVER command; the first 7
 12.4514 +   lines MUST (except for the case of letters) be exactly as follows:
 12.4515 +
 12.4516 +       Subject:
 12.4517 +       From:
 12.4518 +       Date:
 12.4519 +       Message-ID:
 12.4520 +       References:
 12.4521 +       :bytes
 12.4522 +       :lines
 12.4523 +
 12.4524 +   For compatibility with existing implementations, the last two lines
 12.4525 +   MAY instead be:
 12.4526 +
 12.4527 +       Bytes:
 12.4528 +       Lines:
 12.4529 +
 12.4530 +   even though they refer to metadata, not headers.
 12.4531 +
 12.4532 +
 12.4533 +
 12.4534 +
 12.4535 +
 12.4536 +Feather                     Standards Track                    [Page 81]
 12.4537 +
 12.4538 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4539 +
 12.4540 +
 12.4541 +   All subsequent lines MUST consist of either a header name followed by
 12.4542 +   ":full", or the name of a piece of metadata.
 12.4543 +
 12.4544 +   There are no leading or trailing spaces in the output.
 12.4545 +
 12.4546 +   Note that the 7 fixed lines describe the 2nd to 8th fields of the
 12.4547 +   OVER output.  The "full" suffix (which may use either uppercase,
 12.4548 +   lowercase, or a mix) is a reminder that the corresponding fields
 12.4549 +   include the header name.
 12.4550 +
 12.4551 +   This command MAY generate different results if it is used more than
 12.4552 +   once in a session.
 12.4553 +
 12.4554 +   If the OVER command is not implemented, the meaning of the output
 12.4555 +   from this command is not specified, but it must still meet the above
 12.4556 +   syntactic requirements.
 12.4557 +
 12.4558 +8.4.3.  Examples
 12.4559 +
 12.4560 +   Example of LIST OVERVIEW.FMT output corresponding to the example OVER
 12.4561 +   output above, in the preferred format:
 12.4562 +
 12.4563 +      [C] LIST OVERVIEW.FMT
 12.4564 +      [S] 215 Order of fields in overview database.
 12.4565 +      [S] Subject:
 12.4566 +      [S] From:
 12.4567 +      [S] Date:
 12.4568 +      [S] Message-ID:
 12.4569 +      [S] References:
 12.4570 +      [S] :bytes
 12.4571 +      [S] :lines
 12.4572 +      [S] Xref:full
 12.4573 +      [S] Distribution:full
 12.4574 +      [S] .
 12.4575 +
 12.4576 +
 12.4577 +
 12.4578 +
 12.4579 +
 12.4580 +
 12.4581 +
 12.4582 +
 12.4583 +
 12.4584 +
 12.4585 +
 12.4586 +
 12.4587 +
 12.4588 +
 12.4589 +
 12.4590 +
 12.4591 +
 12.4592 +Feather                     Standards Track                    [Page 82]
 12.4593 +
 12.4594 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4595 +
 12.4596 +
 12.4597 +   Example of LIST OVERVIEW.FMT output corresponding to the example OVER
 12.4598 +   output above, in the alternative format:
 12.4599 +
 12.4600 +      [C] LIST OVERVIEW.FMT
 12.4601 +      [S] 215 Order of fields in overview database.
 12.4602 +      [S] Subject:
 12.4603 +      [S] From:
 12.4604 +      [S] Date:
 12.4605 +      [S] Message-ID:
 12.4606 +      [S] References:
 12.4607 +      [S] Bytes:
 12.4608 +      [S] Lines:
 12.4609 +      [S] Xref:FULL
 12.4610 +      [S] Distribution:FULL
 12.4611 +      [S] .
 12.4612 +
 12.4613 +8.5.  HDR
 12.4614 +
 12.4615 +8.5.1.  Usage
 12.4616 +
 12.4617 +   Indicating capability: HDR
 12.4618 +
 12.4619 +   Syntax
 12.4620 +     HDR field message-id
 12.4621 +     HDR field range
 12.4622 +     HDR field
 12.4623 +
 12.4624 +   Responses
 12.4625 +
 12.4626 +   First form (message-id specified)
 12.4627 +     225    Headers follow (multi-line)
 12.4628 +     430    No article with that message-id
 12.4629 +
 12.4630 +   Second form (range specified)
 12.4631 +     225    Headers follow (multi-line)
 12.4632 +     412    No newsgroup selected
 12.4633 +     423    No articles in that range
 12.4634 +
 12.4635 +   Third form (current article number used)
 12.4636 +     225    Headers follow (multi-line)
 12.4637 +     412    No newsgroup selected
 12.4638 +     420    Current article number is invalid
 12.4639 +
 12.4640 +   Parameters
 12.4641 +     field         Name of field
 12.4642 +     range         Number(s) of articles
 12.4643 +     message-id    Message-id of article
 12.4644 +
 12.4645 +
 12.4646 +
 12.4647 +
 12.4648 +Feather                     Standards Track                    [Page 83]
 12.4649 +
 12.4650 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4651 +
 12.4652 +
 12.4653 +8.5.2.  Description
 12.4654 +
 12.4655 +   The HDR command provides access to specific fields from an article
 12.4656 +   specified by message-id, or from a specified article or range of
 12.4657 +   articles in the currently selected newsgroup.  It MAY take the
 12.4658 +   information directly from the articles or from the overview database.
 12.4659 +   In the case of headers, an implementation MAY restrict the use of
 12.4660 +   this command to a specific list of headers or MAY allow it to be used
 12.4661 +   with any header; it may behave differently when it is used with a
 12.4662 +   message-id argument and when it is used with a range or no argument.
 12.4663 +
 12.4664 +   The required field argument is the name of a header with the colon
 12.4665 +   omitted (e.g., "subject") or the name of a metadata item including
 12.4666 +   the leading colon (e.g., ":bytes"), and is case insensitive.
 12.4667 +
 12.4668 +   The message-id argument indicates a specific article.  The range
 12.4669 +   argument may be any of the following:
 12.4670 +
 12.4671 +   o  An article number.
 12.4672 +
 12.4673 +   o  An article number followed by a dash to indicate all following.
 12.4674 +
 12.4675 +   o  An article number followed by a dash followed by another article
 12.4676 +      number.
 12.4677 +
 12.4678 +   If neither is specified, the current article number is used.
 12.4679 +
 12.4680 +   If the information is available, it is returned as a multi-line data
 12.4681 +   block following the 225 response code and contains one line for each
 12.4682 +   article in the range that exists.  (Note that unless the argument is
 12.4683 +   a range including a dash, there will be exactly one line in the data
 12.4684 +   block.)  The line consists of the article number, a space, and then
 12.4685 +   the contents of the field.  In the case of a header, the header name,
 12.4686 +   the colon, and the first space after the colon are all omitted.
 12.4687 +
 12.4688 +   If the article is specified by message-id (the first form of the
 12.4689 +   command), the article number MUST be replaced with zero, except that
 12.4690 +   if there is a currently selected newsgroup and the article is present
 12.4691 +   in that group, the server MAY use the article's number in that group.
 12.4692 +   (See the ARTICLE command (Section 6.2.1) and STAT examples
 12.4693 +   (Section 6.2.4.3) for more details.)  In the other two forms of the
 12.4694 +   command, the article number MUST be returned.
 12.4695 +
 12.4696 +   Header contents are modified as follows: all CRLF pairs are removed,
 12.4697 +   and then each TAB is replaced with a single space.  (Note that this
 12.4698 +   is the same transformation as is performed by the OVER command
 12.4699 +   (Section 8.3.2), and the same comment concerning NUL, CR, and LF
 12.4700 +   applies.)
 12.4701 +
 12.4702 +
 12.4703 +
 12.4704 +Feather                     Standards Track                    [Page 84]
 12.4705 +
 12.4706 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4707 +
 12.4708 +
 12.4709 +   Note the distinction between headers and metadata appearing to have
 12.4710 +   the same meaning.  Headers are always taken unchanged from the
 12.4711 +   article; metadata are always calculated.  For example, a request for
 12.4712 +   "Lines" returns the contents of the "Lines" header of the specified
 12.4713 +   articles, if any, no matter whether they accurately state the number
 12.4714 +   of lines, while a request for ":lines" returns the line count
 12.4715 +   metadata, which is always the actual number of lines irrespective of
 12.4716 +   what any header may state.
 12.4717 +
 12.4718 +   If the requested header is not present in the article, or if it is
 12.4719 +   present but empty, a line for that article is included in the output,
 12.4720 +   but the header content portion of the line is empty (the space after
 12.4721 +   the article number MAY be retained or omitted).  If the header occurs
 12.4722 +   in a given article more than once, only the content of the first
 12.4723 +   occurrence is returned by HDR.  If any article number in the provided
 12.4724 +   range does not exist in the group, no line for that article number is
 12.4725 +   included in the output.
 12.4726 +
 12.4727 +   If the second argument is a message-id and no such article exists, a
 12.4728 +   430 response MUST be returned.  If the second argument is a range or
 12.4729 +   is omitted and the currently selected newsgroup is invalid, a 412
 12.4730 +   response MUST be returned.  If the second argument is a range and no
 12.4731 +   articles in that number range exist in the currently selected
 12.4732 +   newsgroup, including the case where the second number is less than
 12.4733 +   the first one, a 423 response MUST be returned.  If the second
 12.4734 +   argument is omitted and the current article number is invalid, a 420
 12.4735 +   response MUST be returned.
 12.4736 +
 12.4737 +   A server MAY only allow HDR commands for a limited set of fields; it
 12.4738 +   may behave differently in this respect for the first (message-id)
 12.4739 +   form from how it would for the other forms.  If so, it MUST respond
 12.4740 +   with the generic 503 response to attempts to request other fields,
 12.4741 +   rather than return erroneous results, such as a successful empty
 12.4742 +   response.
 12.4743 +
 12.4744 +   If HDR uses the overview database and it is inconsistent for the
 12.4745 +   requested field, the server MAY return what results it can, or it MAY
 12.4746 +   respond with the generic 503 response.  In the latter case, the field
 12.4747 +   MUST NOT appear in the output from LIST HEADERS.
 12.4748 +
 12.4749 +
 12.4750 +
 12.4751 +
 12.4752 +
 12.4753 +
 12.4754 +
 12.4755 +
 12.4756 +
 12.4757 +
 12.4758 +
 12.4759 +
 12.4760 +Feather                     Standards Track                    [Page 85]
 12.4761 +
 12.4762 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4763 +
 12.4764 +
 12.4765 +8.5.3.  Examples
 12.4766 +
 12.4767 +   Example of a successful retrieval of subject lines from a range of
 12.4768 +   articles (3000235 has no Subject header, and 3000236 is missing):
 12.4769 +
 12.4770 +      [C] GROUP misc.test
 12.4771 +      [S] 211 1234 3000234 3002322 misc.test
 12.4772 +      [C] HDR Subject 3000234-3000238
 12.4773 +      [S] 225 Headers follow
 12.4774 +      [S] 3000234 I am just a test article
 12.4775 +      [S] 3000235
 12.4776 +      [S] 3000237 Re: I am just a test article
 12.4777 +      [S] 3000238 Ditto
 12.4778 +      [S] .
 12.4779 +
 12.4780 +   Example of a successful retrieval of line counts from a range of
 12.4781 +   articles:
 12.4782 +
 12.4783 +      [C] GROUP misc.test
 12.4784 +      [S] 211 1234 3000234 3002322 misc.test
 12.4785 +      [C] HDR :lines 3000234-3000238
 12.4786 +      [S] 225 Headers follow
 12.4787 +      [S] 3000234 42
 12.4788 +      [S] 3000235 5
 12.4789 +      [S] 3000237 11
 12.4790 +      [S] 3000238 2378
 12.4791 +      [S] .
 12.4792 +
 12.4793 +   Example of a successful retrieval of the subject line from an article
 12.4794 +   by message-id:
 12.4795 +
 12.4796 +      [C] GROUP misc.test
 12.4797 +      [S] 211 1234 3000234 3002322 misc.test
 12.4798 +      [C] HDR subject <i.am.a.test.article@example.com>
 12.4799 +      [S] 225 Header information follows
 12.4800 +      [S] 0 I am just a test article
 12.4801 +      [S] .
 12.4802 +
 12.4803 +   Example of a successful retrieval of the subject line from the
 12.4804 +   current article:
 12.4805 +
 12.4806 +      [C] GROUP misc.test
 12.4807 +      [S] 211 1234 3000234 3002322 misc.test
 12.4808 +      [C] HDR subject
 12.4809 +      [S] 225 Header information follows
 12.4810 +      [S] 3000234 I am just a test article
 12.4811 +      [S] .
 12.4812 +
 12.4813 +
 12.4814 +
 12.4815 +
 12.4816 +Feather                     Standards Track                    [Page 86]
 12.4817 +
 12.4818 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4819 +
 12.4820 +
 12.4821 +   Example of an unsuccessful retrieval of a header from an article by
 12.4822 +   message-id:
 12.4823 +
 12.4824 +      [C] HDR subject <i.am.not.there@example.com>
 12.4825 +      [S] 430 No Such Article Found
 12.4826 +
 12.4827 +   Example of an unsuccessful retrieval of headers from articles by
 12.4828 +   number because no newsgroup was selected first:
 12.4829 +
 12.4830 +      [Assumes currently selected newsgroup is invalid.]
 12.4831 +      [C] HDR subject 300256-
 12.4832 +      [S] 412 No newsgroup selected
 12.4833 +
 12.4834 +   Example of an unsuccessful retrieval of headers because the currently
 12.4835 +   selected newsgroup is empty:
 12.4836 +
 12.4837 +      [C] GROUP example.empty.newsgroup
 12.4838 +      [S] 211 0 0 0 example.empty.newsgroup
 12.4839 +      [C] HDR subject 1-
 12.4840 +      [S] 423 No articles in that range
 12.4841 +
 12.4842 +   Example of an unsuccessful retrieval of headers because the server
 12.4843 +   does not allow HDR commands for that header:
 12.4844 +
 12.4845 +      [C] GROUP misc.test
 12.4846 +      [S] 211 1234 3000234 3002322 misc.test
 12.4847 +      [C] HDR Content-Type 3000234-3000238
 12.4848 +      [S] 503 HDR not permitted on Content-Type
 12.4849 +
 12.4850 +8.6.  LIST HEADERS
 12.4851 +
 12.4852 +8.6.1.  Usage
 12.4853 +
 12.4854 +   Indicating capability: HDR
 12.4855 +
 12.4856 +   Syntax
 12.4857 +     LIST HEADERS [MSGID|RANGE]
 12.4858 +
 12.4859 +   Responses
 12.4860 +     215    Field list follows (multi-line)
 12.4861 +
 12.4862 +   Parameters
 12.4863 +     MSGID    Requests list for access by message-id
 12.4864 +     RANGE    Requests list for access by range
 12.4865 +
 12.4866 +
 12.4867 +
 12.4868 +
 12.4869 +
 12.4870 +
 12.4871 +
 12.4872 +Feather                     Standards Track                    [Page 87]
 12.4873 +
 12.4874 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4875 +
 12.4876 +
 12.4877 +8.6.2.  Description
 12.4878 +
 12.4879 +   See Section 7.6.1 for general requirements of the LIST command.
 12.4880 +
 12.4881 +   The LIST HEADERS command returns a list of fields that may be
 12.4882 +   retrieved using the HDR command.
 12.4883 +
 12.4884 +   The information is returned as a multi-line data block following the
 12.4885 +   215 response code and contains one line for each field name
 12.4886 +   (excluding the trailing colon for headers and including the leading
 12.4887 +   colon for metadata items).  If the implementation allows any header
 12.4888 +   to be retrieved, it MUST NOT include any header names in the list but
 12.4889 +   MUST include the special entry ":" (a single colon on its own).  It
 12.4890 +   MUST still explicitly list any metadata items that are available.
 12.4891 +   The order of items in the list is not significant; the server need
 12.4892 +   not even consistently return the same order.  The list MAY be empty
 12.4893 +   (though in this circumstance there is little point in providing the
 12.4894 +   HDR command).
 12.4895 +
 12.4896 +   An implementation that also supports the OVER command SHOULD at least
 12.4897 +   permit all the headers and metadata items listed in the output from
 12.4898 +   the LIST OVERVIEW.FMT command.
 12.4899 +
 12.4900 +   If the server treats the first form of the HDR command (message-id
 12.4901 +   specified) differently from the other two forms (range specified or
 12.4902 +   current article number used) in respect of which headers or metadata
 12.4903 +   items are available, then the following apply:
 12.4904 +
 12.4905 +   o  If the MSGID argument is specified, the results MUST be those
 12.4906 +      available for the first form of the HDR command.
 12.4907 +
 12.4908 +   o  If the RANGE argument is specified, the results MUST be those
 12.4909 +      available for the second and third forms of the HDR command.
 12.4910 +
 12.4911 +   o  If no argument is specified, the results MUST be those available
 12.4912 +      in all forms of the HDR command (that is, it MUST only list those
 12.4913 +      items listed in both the previous cases).
 12.4914 +
 12.4915 +   If the server does not treat the various forms differently, then it
 12.4916 +   MUST ignore any argument and always produce the same results (though
 12.4917 +   not necessarily always in the same order).
 12.4918 +
 12.4919 +   If the HDR command is not implemented, the meaning of the output from
 12.4920 +   this command is not specified, but it must still meet the above
 12.4921 +   syntactic requirements.
 12.4922 +
 12.4923 +
 12.4924 +
 12.4925 +
 12.4926 +
 12.4927 +
 12.4928 +Feather                     Standards Track                    [Page 88]
 12.4929 +
 12.4930 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4931 +
 12.4932 +
 12.4933 +8.6.3.  Examples
 12.4934 +
 12.4935 +   Example of an implementation providing access to only a few headers:
 12.4936 +
 12.4937 +      [C] LIST HEADERS
 12.4938 +      [S] 215 headers supported:
 12.4939 +      [S] Subject
 12.4940 +      [S] Message-ID
 12.4941 +      [S] Xref
 12.4942 +      [S] .
 12.4943 +
 12.4944 +   Example of an implementation providing access to the same fields as
 12.4945 +   the first example in Section 8.4.3:
 12.4946 +
 12.4947 +      [C] CAPABILITIES
 12.4948 +      [S] 101 Capability list:
 12.4949 +      [S] VERSION 2
 12.4950 +      [S] READER
 12.4951 +      [S] OVER
 12.4952 +      [S] HDR
 12.4953 +      [S] LIST ACTIVE NEWSGROUPS HEADERS OVERVIEW.FMT
 12.4954 +      [S] .
 12.4955 +      [C] LIST HEADERS
 12.4956 +      [S] 215 headers and metadata items supported:
 12.4957 +      [S] Date
 12.4958 +      [S] Distribution
 12.4959 +      [S] From
 12.4960 +      [S] Message-ID
 12.4961 +      [S] References
 12.4962 +      [S] Subject
 12.4963 +      [S] Xref
 12.4964 +      [S] :bytes
 12.4965 +      [S] :lines
 12.4966 +      [S] .
 12.4967 +
 12.4968 +   Example of an implementation providing access to all headers:
 12.4969 +
 12.4970 +      [C] LIST HEADERS
 12.4971 +      [S] 215 metadata items supported:
 12.4972 +      [S] :
 12.4973 +      [S] :lines
 12.4974 +      [S] :bytes
 12.4975 +      [S] :x-article-number
 12.4976 +      [S] .
 12.4977 +
 12.4978 +
 12.4979 +
 12.4980 +
 12.4981 +
 12.4982 +
 12.4983 +
 12.4984 +Feather                     Standards Track                    [Page 89]
 12.4985 +
 12.4986 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.4987 +
 12.4988 +
 12.4989 +   Example of an implementation distinguishing the first form of the HDR
 12.4990 +   command from the other two forms:
 12.4991 +
 12.4992 +      [C] LIST HEADERS RANGE
 12.4993 +      [S] 215 metadata items supported:
 12.4994 +      [S] :
 12.4995 +      [S] :lines
 12.4996 +      [S] :bytes
 12.4997 +      [S] .
 12.4998 +      [C] LIST HEADERS MSGID
 12.4999 +      [S] 215 headers and metadata items supported:
 12.5000 +      [S] Date
 12.5001 +      [S] Distribution
 12.5002 +      [S] From
 12.5003 +      [S] Message-ID
 12.5004 +      [S] References
 12.5005 +      [S] Subject
 12.5006 +      [S] :lines
 12.5007 +      [S] :bytes
 12.5008 +      [S] :x-article-number
 12.5009 +      [S] .
 12.5010 +      [C] LIST HEADERS
 12.5011 +      [S] 215 headers and metadata items supported:
 12.5012 +      [S] Date
 12.5013 +      [S] Distribution
 12.5014 +      [S] From
 12.5015 +      [S] Message-ID
 12.5016 +      [S] References
 12.5017 +      [S] Subject
 12.5018 +      [S] :lines
 12.5019 +      [S] :bytes
 12.5020 +      [S] .
 12.5021 +
 12.5022 +   Note that :x-article-number does not appear in the last set of
 12.5023 +   output.
 12.5024 +
 12.5025 +9.  Augmented BNF Syntax for NNTP
 12.5026 +
 12.5027 +9.1.  Introduction
 12.5028 +
 12.5029 +   Each of the following sections describes the syntax of a major
 12.5030 +   element of NNTP.  This syntax extends and refines the descriptions
 12.5031 +   elsewhere in this specification and should be given precedence when
 12.5032 +   resolving apparent conflicts.  Note that ABNF [RFC4234] strings are
 12.5033 +   case insensitive.  Non-terminals used in several places are defined
 12.5034 +   in a separate section at the end.
 12.5035 +
 12.5036 +
 12.5037 +
 12.5038 +
 12.5039 +
 12.5040 +Feather                     Standards Track                    [Page 90]
 12.5041 +
 12.5042 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5043 +
 12.5044 +
 12.5045 +   Between them, the non-terminals <command-line>, <command-datastream>,
 12.5046 +   <command-continuation>, and <response> specify the text that flows
 12.5047 +   between client and server.  A consistent naming scheme is used in
 12.5048 +   this document for the non-terminals relating to each command, and
 12.5049 +   SHOULD be used by the specification of registered extensions.
 12.5050 +
 12.5051 +   For each command, the sequence is as follows:
 12.5052 +
 12.5053 +   o  The client sends an instance of <command-line>; the syntax for the
 12.5054 +      EXAMPLE command is <example-command>.
 12.5055 +
 12.5056 +   o  If the client is one that immediately streams data, it sends an
 12.5057 +      instance of <command-datastream>; the syntax for the EXAMPLE
 12.5058 +      command is <example-datastream>.
 12.5059 +
 12.5060 +   o  The server sends an instance of <response>.
 12.5061 +
 12.5062 +      *  The initial response line is independent of the command that
 12.5063 +         generated it; if the 000 response has arguments, the syntax of
 12.5064 +         the initial line is <response-000-content>.
 12.5065 +
 12.5066 +      *  If the response is multi-line, the initial line is followed by
 12.5067 +         a <multi-line-data-block>.  The syntax for the contents of this
 12.5068 +         block after "dot-stuffing" has been removed is (for the 000
 12.5069 +         response to the EXAMPLE command) <example-000-ml-content> and
 12.5070 +         is an instance of <multi-line-response-content>.
 12.5071 +
 12.5072 +   o  While the latest response is one that indicates more data is
 12.5073 +      required (in general, a 3xx response):
 12.5074 +
 12.5075 +      *  the client sends an instance of <command-continuation>; the
 12.5076 +         syntax for the EXAMPLE continuation following a 333 response is
 12.5077 +         <example-333-continuation>;
 12.5078 +
 12.5079 +      *  the server sends another instance of <response>, as above.
 12.5080 +
 12.5081 +   (There are no commands in this specification that immediately stream
 12.5082 +   data, but this non-terminal is defined for the convenience of
 12.5083 +   extensions.)
 12.5084 +
 12.5085 +
 12.5086 +
 12.5087 +
 12.5088 +
 12.5089 +
 12.5090 +
 12.5091 +
 12.5092 +
 12.5093 +
 12.5094 +
 12.5095 +
 12.5096 +Feather                     Standards Track                    [Page 91]
 12.5097 +
 12.5098 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5099 +
 12.5100 +
 12.5101 +9.2.  Commands
 12.5102 +
 12.5103 +   This syntax defines the non-terminal <command-line>, which represents
 12.5104 +   what is sent from the client to the server (see section 3.1 for
 12.5105 +   limits on lengths).
 12.5106 +
 12.5107 +     command-line = command EOL
 12.5108 +     command = X-command
 12.5109 +     X-command = keyword *(WS token)
 12.5110 +
 12.5111 +     command =/ article-command /
 12.5112 +           body-command /
 12.5113 +           capabilities-command /
 12.5114 +           date-command /
 12.5115 +           group-command /
 12.5116 +           hdr-command /
 12.5117 +           head-command /
 12.5118 +           help-command /
 12.5119 +           ihave-command /
 12.5120 +           last-command /
 12.5121 +           list-command /
 12.5122 +           listgroup-command /
 12.5123 +           mode-reader-command /
 12.5124 +           newgroups-command /
 12.5125 +           newnews-command /
 12.5126 +           next-command /
 12.5127 +           over-command /
 12.5128 +           post-command /
 12.5129 +           quit-command /
 12.5130 +           stat-command
 12.5131 +
 12.5132 +     article-command = "ARTICLE" [WS article-ref]
 12.5133 +     body-command = "BODY" [WS article-ref]
 12.5134 +     capabilities-command = "CAPABILITIES" [WS keyword]
 12.5135 +     date-command = "DATE"
 12.5136 +     group-command = "GROUP" [WS newsgroup-name]
 12.5137 +     hdr-command = "HDR" WS header-meta-name [WS range-ref]
 12.5138 +     head-command = "HEAD" [WS article-ref]
 12.5139 +     help-command = "HELP"
 12.5140 +     ihave-command = "IHAVE" WS message-id
 12.5141 +     last-command = "LAST"
 12.5142 +     list-command = "LIST" [WS list-arguments]
 12.5143 +     listgroup-command = "LISTGROUP" [WS newsgroup-name [WS range]]
 12.5144 +     mode-reader-command = "MODE" WS "READER"
 12.5145 +     newgroups-command = "NEWGROUPS" WS date-time
 12.5146 +     newnews-command = "NEWNEWS" WS wildmat WS date-time
 12.5147 +     next-command = "NEXT"
 12.5148 +     over-command = "OVER" [WS range-ref]
 12.5149 +
 12.5150 +
 12.5151 +
 12.5152 +Feather                     Standards Track                    [Page 92]
 12.5153 +
 12.5154 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5155 +
 12.5156 +
 12.5157 +     post-command = "POST"
 12.5158 +     quit-command = "QUIT"
 12.5159 +     stat-command = "STAT" [WS article-ref]
 12.5160 +
 12.5161 +     article-ref = article-number / message-id
 12.5162 +     date = date2y / date4y
 12.5163 +     date4y = 4DIGIT 2DIGIT 2DIGIT
 12.5164 +     date2y = 2DIGIT 2DIGIT 2DIGIT
 12.5165 +     date-time = date WS time [WS "GMT"]
 12.5166 +     header-meta-name = header-name / metadata-name
 12.5167 +     list-arguments = keyword [WS token]
 12.5168 +     metadata-name = ":" 1*A-NOTCOLON
 12.5169 +     range = article-number ["-" [article-number]]
 12.5170 +     range-ref = range / message-id
 12.5171 +     time = 2DIGIT 2DIGIT 2DIGIT
 12.5172 +
 12.5173 +9.3.  Command Continuation
 12.5174 +
 12.5175 +   This syntax defines the further material sent by the client in the
 12.5176 +   case of multi-stage commands and those that stream data.
 12.5177 +
 12.5178 +     command-datastream = UNDEFINED
 12.5179 +       ; not used, provided as a hook for extensions
 12.5180 +     command-continuation = ihave-335-continuation /
 12.5181 +           post-340-continuation
 12.5182 +
 12.5183 +     ihave-335-continuation = encoded-article
 12.5184 +     post-340-continuation = encoded-article
 12.5185 +
 12.5186 +     encoded-article = multi-line-data-block
 12.5187 +       ; after undoing the "dot-stuffing", this MUST match <article>
 12.5188 +
 12.5189 +9.4.  Responses
 12.5190 +
 12.5191 +9.4.1.  Generic Responses
 12.5192 +
 12.5193 +   This syntax defines the non-terminal <response>, which represents the
 12.5194 +   generic form of responses; that is, what is sent from the server to
 12.5195 +   the client in response to a <command> or a <command-continuation>.
 12.5196 +
 12.5197 +     response = simple-response / multi-line-response
 12.5198 +     simple-response = initial-response-line
 12.5199 +     multi-line-response = initial-response-line multi-line-data-block
 12.5200 +
 12.5201 +     initial-response-line =
 12.5202 +           initial-response-content [SP trailing-comment] CRLF
 12.5203 +     initial-response-content = X-initial-response-content
 12.5204 +     X-initial-response-content = 3DIGIT *(SP response-argument)
 12.5205 +
 12.5206 +
 12.5207 +
 12.5208 +Feather                     Standards Track                    [Page 93]
 12.5209 +
 12.5210 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5211 +
 12.5212 +
 12.5213 +     response-argument = 1*A-CHAR
 12.5214 +     trailing-comment = *U-CHAR
 12.5215 +
 12.5216 +9.4.2.  Initial Response Line Contents
 12.5217 +
 12.5218 +   This syntax defines the specific initial response lines for the
 12.5219 +   various commands in this specification (see section 3.1 for limits on
 12.5220 +   lengths).  Only those response codes with arguments are listed.
 12.5221 +
 12.5222 +     initial-response-content =/ response-111-content /
 12.5223 +           response-211-content /
 12.5224 +           response-220-content /
 12.5225 +           response-221-content /
 12.5226 +           response-222-content /
 12.5227 +           response-223-content /
 12.5228 +           response-401-content
 12.5229 +
 12.5230 +     response-111-content = "111" SP date4y time
 12.5231 +     response-211-content = "211" 3(SP article-number) SP newsgroup-name
 12.5232 +     response-220-content = "220" SP article-number SP message-id
 12.5233 +     response-221-content = "221" SP article-number SP message-id
 12.5234 +     response-222-content = "222" SP article-number SP message-id
 12.5235 +     response-223-content = "223" SP article-number SP message-id
 12.5236 +     response-401-content = "401" SP capability-label
 12.5237 +
 12.5238 +9.4.3.  Multi-line Response Contents
 12.5239 +
 12.5240 +   This syntax defines the content of the various multi-line responses;
 12.5241 +   more precisely, it defines the part of the response in the multi-line
 12.5242 +   data block after any "dot-stuffing" has been undone.  The numeric
 12.5243 +   portion of each non-terminal name indicates the response code that is
 12.5244 +   followed by this data.
 12.5245 +
 12.5246 +     multi-line-response-content = article-220-ml-content /
 12.5247 +           body-222-ml-content /
 12.5248 +           capabilities-101-ml-content /
 12.5249 +           hdr-225-ml-content /
 12.5250 +           head-221-ml-content /
 12.5251 +           help-100-ml-content /
 12.5252 +           list-215-ml-content /
 12.5253 +           listgroup-211-ml-content /
 12.5254 +           newgroups-231-ml-content /
 12.5255 +           newnews-230-ml-content /
 12.5256 +           over-224-ml-content
 12.5257 +
 12.5258 +     article-220-ml-content = article
 12.5259 +     body-222-ml-content = body
 12.5260 +     capabilities-101-ml-content = version-line CRLF
 12.5261 +
 12.5262 +
 12.5263 +
 12.5264 +Feather                     Standards Track                    [Page 94]
 12.5265 +
 12.5266 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5267 +
 12.5268 +
 12.5269 +           *(capability-line CRLF)
 12.5270 +     hdr-225-ml-content = *(article-number SP hdr-content CRLF)
 12.5271 +     head-221-ml-content = 1*header
 12.5272 +     help-100-ml-content = *(*U-CHAR CRLF)
 12.5273 +     list-215-ml-content = list-content
 12.5274 +     listgroup-211-ml-content = *(article-number CRLF)
 12.5275 +     newgroups-231-ml-content = active-groups-list
 12.5276 +     newnews-230-ml-content = *(message-id CRLF)
 12.5277 +     over-224-ml-content = *(article-number over-content CRLF)
 12.5278 +
 12.5279 +     active-groups-list = *(newsgroup-name SPA article-number
 12.5280 +           SPA article-number SPA newsgroup-status CRLF)
 12.5281 +     hdr-content = *S-NONTAB
 12.5282 +     hdr-n-content = [(header-name ":" / metadata-name) SP hdr-content]
 12.5283 +     list-content = body
 12.5284 +     newsgroup-status = %x79 / %x6E / %x6D / private-status
 12.5285 +     over-content = 1*6(TAB hdr-content) /
 12.5286 +           7(TAB hdr-content) *(TAB hdr-n-content)
 12.5287 +     private-status = token ; except the values in newsgroup-status
 12.5288 +
 12.5289 +9.5.  Capability Lines
 12.5290 +
 12.5291 +   This syntax defines the generic form of a capability line in the
 12.5292 +   capabilities list (see Section 3.3.1).
 12.5293 +
 12.5294 +     capability-line = capability-entry
 12.5295 +     capability-entry = X-capability-entry
 12.5296 +     X-capability-entry = capability-label *(WS capability-argument)
 12.5297 +     capability-label = keyword
 12.5298 +     capability-argument = token
 12.5299 +
 12.5300 +   This syntax defines the specific capability entries for the
 12.5301 +   capabilities in this specification.
 12.5302 +
 12.5303 +     capability-entry =/
 12.5304 +           hdr-capability /
 12.5305 +           ihave-capability /
 12.5306 +           implementation-capability /
 12.5307 +           list-capability /
 12.5308 +           mode-reader-capability /
 12.5309 +           newnews-capability /
 12.5310 +           over-capability /
 12.5311 +           post-capability /
 12.5312 +           reader-capability
 12.5313 +
 12.5314 +     hdr-capability = "HDR"
 12.5315 +     ihave-capability = "IHAVE"
 12.5316 +     implementation-capability = "IMPLEMENTATION" *(WS token)
 12.5317 +
 12.5318 +
 12.5319 +
 12.5320 +Feather                     Standards Track                    [Page 95]
 12.5321 +
 12.5322 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5323 +
 12.5324 +
 12.5325 +     list-capability = "LIST" 1*(WS keyword)
 12.5326 +     mode-reader-capability = "MODE-READER"
 12.5327 +     newnews-capability = "NEWNEWS"
 12.5328 +     over-capability = "OVER" [WS "MSGID"]
 12.5329 +     post-capability = "POST"
 12.5330 +     reader-capability = "READER"
 12.5331 +
 12.5332 +     version-line = "VERSION" 1*(WS version-number)
 12.5333 +     version-number = nzDIGIT *5DIGIT
 12.5334 +
 12.5335 +9.6.  LIST Variants
 12.5336 +
 12.5337 +   This section defines more specifically the keywords for the LIST
 12.5338 +   command and the syntax of the corresponding response contents.
 12.5339 +
 12.5340 +     ; active
 12.5341 +     list-arguments =/ "ACTIVE" [WS wildmat]
 12.5342 +     list-content =/ list-active-content
 12.5343 +     list-active-content = active-groups-list
 12.5344 +
 12.5345 +
 12.5346 +     ; active.times
 12.5347 +     list-arguments =/ "ACTIVE.TIMES" [WS wildmat]
 12.5348 +     list-content =/ list-active-times-content
 12.5349 +     list-active-times-content =
 12.5350 +           *(newsgroup-name SPA 1*DIGIT SPA newsgroup-creator CRLF)
 12.5351 +     newsgroup-creator = U-TEXT
 12.5352 +
 12.5353 +
 12.5354 +     ; distrib.pats
 12.5355 +     list-arguments =/ "DISTRIB.PATS"
 12.5356 +     list-content =/ list-distrib-pats-content
 12.5357 +     list-distrib-pats-content =
 12.5358 +           *(1*DIGIT ":" wildmat ":" distribution CRLF)
 12.5359 +     distribution = token
 12.5360 +
 12.5361 +
 12.5362 +     ; headers
 12.5363 +     list-arguments =/ "HEADERS" [WS ("MSGID" / "RANGE")]
 12.5364 +     list-content =/ list-headers-content
 12.5365 +     list-headers-content = *(header-meta-name CRLF) /
 12.5366 +           *((metadata-name / ":") CRLF)
 12.5367 +
 12.5368 +
 12.5369 +     ; newsgroups
 12.5370 +     list-arguments =/ "NEWSGROUPS" [WS wildmat]
 12.5371 +     list-content =/ list-newsgroups-content
 12.5372 +     list-newsgroups-content =
 12.5373 +
 12.5374 +
 12.5375 +
 12.5376 +Feather                     Standards Track                    [Page 96]
 12.5377 +
 12.5378 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5379 +
 12.5380 +
 12.5381 +           *(newsgroup-name WS newsgroup-description CRLF)
 12.5382 +     newsgroup-description = S-TEXT
 12.5383 +
 12.5384 +
 12.5385 +     ; overview.fmt
 12.5386 +     list-arguments =/ "OVERVIEW.FMT"
 12.5387 +     list-content =/ list-overview-fmt-content
 12.5388 +     list-overview-fmt-content = "Subject:" CRLF
 12.5389 +           "From:" CRLF
 12.5390 +           "Date:" CRLF
 12.5391 +           "Message-ID:" CRLF
 12.5392 +           "References:" CRLF
 12.5393 +           ( ":bytes" CRLF ":lines" / "Bytes:" CRLF "Lines:") CRLF
 12.5394 +           *((header-name ":full" / metadata-name) CRLF)
 12.5395 +
 12.5396 +9.7.  Articles
 12.5397 +
 12.5398 +   This syntax defines the non-terminal <article>, which represents the
 12.5399 +   format of an article as described in Section 3.6.
 12.5400 +
 12.5401 +     article = 1*header CRLF body
 12.5402 +     header = header-name ":" [CRLF] SP header-content CRLF
 12.5403 +     header-content = *(S-CHAR / [CRLF] WS)
 12.5404 +     body = *(*B-CHAR CRLF)
 12.5405 +
 12.5406 +9.8.  General Non-terminals
 12.5407 +
 12.5408 +   These non-terminals are used at various places in the syntax and are
 12.5409 +   collected here for convenience.  A few of these non-terminals are not
 12.5410 +   used in this specification but are provided for the consistency and
 12.5411 +   convenience of extension authors.
 12.5412 +
 12.5413 +     multi-line-data-block = content-lines termination
 12.5414 +     content-lines = *([content-text] CRLF)
 12.5415 +     content-text = (".." / B-NONDOT) *B-CHAR
 12.5416 +     termination = "." CRLF
 12.5417 +
 12.5418 +     article-number = 1*16DIGIT
 12.5419 +     header-name = 1*A-NOTCOLON
 12.5420 +     keyword = ALPHA 2*(ALPHA / DIGIT / "." / "-")
 12.5421 +     message-id = "<" 1*248A-NOTGT ">"
 12.5422 +     newsgroup-name = 1*wildmat-exact
 12.5423 +     token = 1*P-CHAR
 12.5424 +
 12.5425 +     wildmat = wildmat-pattern *("," ["!"] wildmat-pattern)
 12.5426 +     wildmat-pattern = 1*wildmat-item
 12.5427 +     wildmat-item = wildmat-exact / wildmat-wild
 12.5428 +     wildmat-exact = %x22-29 / %x2B / %x2D-3E / %x40-5A / %x5E-7E /
 12.5429 +
 12.5430 +
 12.5431 +
 12.5432 +Feather                     Standards Track                    [Page 97]
 12.5433 +
 12.5434 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5435 +
 12.5436 +
 12.5437 +          UTF8-non-ascii  ; exclude ! * , ? [ \ ]
 12.5438 +     wildmat-wild = "*" / "?"
 12.5439 +
 12.5440 +     base64 = *(4base64-char) [base64-terminal]
 12.5441 +     base64-char = UPPER / LOWER / DIGIT / "+" / "/"
 12.5442 +     base64-terminal = 2base64-char "==" / 3base64-char "="
 12.5443 +
 12.5444 +     ; Assorted special character sets
 12.5445 +     ;   A- means based on US-ASCII, excluding controls and SP
 12.5446 +     ;   P- means based on UTF-8, excluding controls and SP
 12.5447 +     ;   U- means based on UTF-8, excluding NUL CR and LF
 12.5448 +     ;   B- means based on bytes, excluding NUL CR and LF
 12.5449 +     A-CHAR     = %x21-7E
 12.5450 +     A-NOTCOLON = %x21-39 / %x3B-7E  ; exclude ":"
 12.5451 +     A-NOTGT    = %x21-3D / %x3F-7E  ; exclude ">"
 12.5452 +     P-CHAR     = A-CHAR / UTF8-non-ascii
 12.5453 +     U-CHAR     = CTRL / TAB / SP / A-CHAR / UTF8-non-ascii
 12.5454 +     U-NONTAB   = CTRL /       SP / A-CHAR / UTF8-non-ascii
 12.5455 +     U-TEXT     = P-CHAR *U-CHAR
 12.5456 +     B-CHAR     = CTRL / TAB / SP / %x21-FF
 12.5457 +     B-NONDOT   = CTRL / TAB / SP / %x21-2D / %x2F-FF  ; exclude "."
 12.5458 +
 12.5459 +     ALPHA = UPPER / LOWER   ; use only when case-insensitive
 12.5460 +     CR = %x0D
 12.5461 +     CRLF = CR LF
 12.5462 +     CTRL = %x01-08 / %x0B-0C / %x0E-1F
 12.5463 +     DIGIT = %x30-39
 12.5464 +     nzDIGIT = %x31-39
 12.5465 +     EOL = *(SP / TAB) CRLF
 12.5466 +     LF = %x0A
 12.5467 +     LOWER = %x61-7A
 12.5468 +     SP = %x20
 12.5469 +     SPA = 1*SP
 12.5470 +     TAB = %x09
 12.5471 +     UPPER = %x41-5A
 12.5472 +     UTF8-non-ascii = UTF8-2 / UTF8-3 / UTF8-4
 12.5473 +     UTF8-2    = %xC2-DF UTF8-tail
 12.5474 +     UTF8-3    = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2UTF8-tail /
 12.5475 +                 %xED %x80-9F UTF8-tail / %xEE-EF 2UTF8-tail
 12.5476 +     UTF8-4    = %xF0 %x90-BF 2UTF8-tail / %xF1-F3 3UTF8-tail /
 12.5477 +                 %xF4 %x80-8F 2UTF8-tail
 12.5478 +     UTF8-tail = %x80-BF
 12.5479 +     WS = 1*(SP / TAB)
 12.5480 +
 12.5481 +   The following non-terminals require special consideration.  They
 12.5482 +   represent situations where material SHOULD be restricted to UTF-8,
 12.5483 +   but implementations MUST be able to cope with other character
 12.5484 +   encodings.  Therefore, there are two sets of definitions for them.
 12.5485 +
 12.5486 +
 12.5487 +
 12.5488 +Feather                     Standards Track                    [Page 98]
 12.5489 +
 12.5490 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5491 +
 12.5492 +
 12.5493 +   Implementations MUST accept any content that meets this syntax:
 12.5494 +
 12.5495 +     S-CHAR   = %x21-FF
 12.5496 +     S-NONTAB = CTRL / SP / S-CHAR
 12.5497 +     S-TEXT   = (CTRL / S-CHAR) *B-CHAR
 12.5498 +
 12.5499 +   and MAY pass such content on unaltered.
 12.5500 +
 12.5501 +   When generating new content or re-encoding existing content,
 12.5502 +   implementations SHOULD conform to this syntax:
 12.5503 +
 12.5504 +     S-CHAR   = P-CHAR
 12.5505 +     S-NONTAB = U-NONTAB
 12.5506 +     S-TEXT   = U-TEXT
 12.5507 +
 12.5508 +9.9.  Extensions and Validation
 12.5509 +
 12.5510 +   The specification of a registered extension MUST include formal
 12.5511 +   syntax that defines additional forms for the following non-terminals:
 12.5512 +
 12.5513 +   command
 12.5514 +      for each new command other than a variant of the LIST command -
 12.5515 +      the syntax of each command MUST be compatible with the definition
 12.5516 +      of <X-command>;
 12.5517 +
 12.5518 +   command-datastream
 12.5519 +      for each new command that immediately streams data;
 12.5520 +
 12.5521 +   command-continuation
 12.5522 +      for each new command that sends further material after the initial
 12.5523 +      command line - the syntax of each continuation MUST be exactly
 12.5524 +      what is sent to the server, including any escape mechanisms such
 12.5525 +      as "dot-stuffing";
 12.5526 +
 12.5527 +   initial-response-content
 12.5528 +      for each new response code that has arguments - the syntax of each
 12.5529 +      response MUST be compatible with the definition of <X-initial-
 12.5530 +      response-content>;
 12.5531 +
 12.5532 +   multi-line-response-content
 12.5533 +      for each new response code that has a multi-line response - the
 12.5534 +      syntax MUST show the response after the lines containing the
 12.5535 +      response code and the terminating octet have been removed and any
 12.5536 +      "dot-stuffing" undone;
 12.5537 +
 12.5538 +   capability-entry
 12.5539 +      for each new capability label - the syntax of each entry MUST be
 12.5540 +      compatible with the definition of <X-capability-entry>;
 12.5541 +
 12.5542 +
 12.5543 +
 12.5544 +Feather                     Standards Track                    [Page 99]
 12.5545 +
 12.5546 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5547 +
 12.5548 +
 12.5549 +   list-arguments
 12.5550 +      for each new variant of the LIST command - the syntax of each
 12.5551 +      entry MUST be compatible with the definition of <X-command>;
 12.5552 +
 12.5553 +   list-content
 12.5554 +      for each new variant of the LIST command - the syntax MUST show
 12.5555 +      the response after the lines containing the 215 response code and
 12.5556 +      the terminating octet have been removed and any "dot-stuffing"
 12.5557 +      undone.
 12.5558 +
 12.5559 +   The =/ notation of ABNF [RFC4234] and the naming conventions
 12.5560 +   described in Section 9.1 SHOULD be used for this.
 12.5561 +
 12.5562 +   When the syntax in this specification, or syntax based on it, is
 12.5563 +   validated, it should be noted that:
 12.5564 +
 12.5565 +   o  the non-terminals <command-line>, <command-datastream>,
 12.5566 +      <command-continuation>, <response>, and
 12.5567 +      <multi-line-response-content> describe basic concepts of the
 12.5568 +      protocol and are not referred to by any other rule;
 12.5569 +
 12.5570 +   o  the non-terminal <base64> is provided for the convenience of
 12.5571 +      extension authors and is not referred to by any rule in this
 12.5572 +      specification;
 12.5573 +
 12.5574 +   o  for the reasons given above, the non-terminals <S-CHAR>,
 12.5575 +      <S-NONTAB>, and <S-TEXT> each have two definitions; and
 12.5576 +
 12.5577 +   o  the non-terminal <UNDEFINED> is deliberately not defined.
 12.5578 +
 12.5579 +10.  Internationalisation Considerations
 12.5580 +
 12.5581 +10.1.  Introduction and Historical Situation
 12.5582 +
 12.5583 +   RFC 977 [RFC977] was written at a time when internationalisation was
 12.5584 +   not seen as a significant issue.  As such, it was written on the
 12.5585 +   assumption that all communication would be in ASCII and use only a
 12.5586 +   7-bit transport layer, although in practice just about all known
 12.5587 +   implementations are 8-bit clean.
 12.5588 +
 12.5589 +   Since then, Usenet and NNTP have spread throughout the world.  In the
 12.5590 +   absence of standards for handling the issues of language and
 12.5591 +   character sets, countries, newsgroup hierarchies, and individuals
 12.5592 +   have found a variety of solutions that work for them but that are not
 12.5593 +   necessarily appropriate elsewhere.  For example, some have adopted a
 12.5594 +   default 8-bit character set appropriate to their needs (such as
 12.5595 +   ISO/IEC 8859-1 in Western Europe or KOI-8 in Russia), others have
 12.5596 +   used ASCII (either US-ASCII or national variants) in headers but
 12.5597 +
 12.5598 +
 12.5599 +
 12.5600 +Feather                     Standards Track                   [Page 100]
 12.5601 +
 12.5602 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5603 +
 12.5604 +
 12.5605 +   local 16-bit character sets in article bodies, and still others have
 12.5606 +   gone for a combination of MIME [RFC2045] and UTF-8.  With the
 12.5607 +   increased use of MIME in email, it is becoming more common to find
 12.5608 +   NNTP articles containing MIME headers that identify the character set
 12.5609 +   of the body, but this is far from universal.
 12.5610 +
 12.5611 +   The resulting confusion does not help interoperability.
 12.5612 +
 12.5613 +   One point that has been generally accepted is that articles can
 12.5614 +   contain octets with the top bit set, and NNTP is only expected to
 12.5615 +   operate on 8-bit clean transport paths.
 12.5616 +
 12.5617 +10.2.  This Specification
 12.5618 +
 12.5619 +   Part of the role of this present specification is to eliminate this
 12.5620 +   confusion and promote interoperability as far as possible.  At the
 12.5621 +   same time, it is necessary to accept the existence of the present
 12.5622 +   situation and not break existing implementations and arrangements
 12.5623 +   gratuitously, even if they are less than optimal.  Therefore, the
 12.5624 +   current practice described above has been taken into consideration in
 12.5625 +   producing this specification.
 12.5626 +
 12.5627 +   This specification extends NNTP from US-ASCII [ANSI1986] to UTF-8
 12.5628 +   [RFC3629].  Except in the two areas discussed below, UTF-8 (which is
 12.5629 +   a superset of US-ASCII) is mandatory, and implementations MUST NOT
 12.5630 +   use any other encoding.
 12.5631 +
 12.5632 +   Firstly, the use of MIME for article headers and bodies is strongly
 12.5633 +   recommended.  However, given widely divergent existing practices, an
 12.5634 +   attempt to require a particular encoding and tagging standard would
 12.5635 +   be premature at this time.  Accordingly, this specification allows
 12.5636 +   the use of arbitrary 8-bit data in articles subject to the following
 12.5637 +   requirements and recommendations.
 12.5638 +
 12.5639 +   o  The names of headers (e.g., "From" or "Subject") MUST be in
 12.5640 +      US-ASCII.
 12.5641 +
 12.5642 +   o  Header values SHOULD use US-ASCII or an encoding based on it, such
 12.5643 +      as RFC 2047 [RFC2047], until such time as another approach has
 12.5644 +      been standardised.  At present, 8-bit encodings (including UTF-8)
 12.5645 +      SHOULD NOT be used because they are likely to cause
 12.5646 +      interoperability problems.
 12.5647 +
 12.5648 +   o  The character set of article bodies SHOULD be indicated in the
 12.5649 +      article headers, and this SHOULD be done in accordance with MIME.
 12.5650 +
 12.5651 +   o  Where an article is obtained from an external source, an
 12.5652 +      implementation MAY pass it on and derive data from it (such as the
 12.5653 +
 12.5654 +
 12.5655 +
 12.5656 +Feather                     Standards Track                   [Page 101]
 12.5657 +
 12.5658 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5659 +
 12.5660 +
 12.5661 +      response to the HDR command), even though the article or the data
 12.5662 +      does not meet the above requirements.  Implementations MUST
 12.5663 +      transfer such articles and data correctly and unchanged; they MUST
 12.5664 +      NOT attempt to convert or re-encode the article or derived data.
 12.5665 +      (Nevertheless, a client or server MAY elect not to post or forward
 12.5666 +      the article if, after further examination of the article, it deems
 12.5667 +      it inappropriate to do so.)
 12.5668 +
 12.5669 +   This requirement affects the ARTICLE (Section 6.2.1), BODY
 12.5670 +   (Section 6.2.3), HDR (Section 8.5), HEAD (Section 6.2.2), IHAVE
 12.5671 +   (Section 6.3.2), OVER (Section 8.3), and POST (Section 6.3.1)
 12.5672 +   commands.
 12.5673 +
 12.5674 +   Secondly, the following requirements are placed on the newsgroups
 12.5675 +   list returned by the LIST NEWSGROUPS command (Section 7.6.6):
 12.5676 +
 12.5677 +   o  Although this specification allows UTF-8 for newsgroup names, they
 12.5678 +      SHOULD be restricted to US-ASCII until a successor to RFC 1036
 12.5679 +      [RFC1036] standardises another approach. 8-bit encodings SHOULD
 12.5680 +      NOT be used because they are likely to cause interoperability
 12.5681 +      problems.
 12.5682 +
 12.5683 +   o  The newsgroup description SHOULD be in US-ASCII or UTF-8 unless
 12.5684 +      and until a successor to RFC 1036 standardises other encoding
 12.5685 +      arrangements.  8-bit encodings other than UTF-8 SHOULD NOT be used
 12.5686 +      because they are likely to cause interoperability problems.
 12.5687 +
 12.5688 +   o  Implementations that obtain this data from an external source MUST
 12.5689 +      handle it correctly even if it does not meet the above
 12.5690 +      requirements.  Implementations (in particular, clients) MUST
 12.5691 +      handle such data correctly.
 12.5692 +
 12.5693 +10.3.  Outstanding Issues
 12.5694 +
 12.5695 +   While the primary use of NNTP is for transmitting articles that
 12.5696 +   conform to RFC 1036 (Netnews articles), it is also used for other
 12.5697 +   formats (see Appendix A).  It is therefore most appropriate that
 12.5698 +   internationalisation issues related to article formats be addressed
 12.5699 +   in the relevant specifications.  For Netnews articles, this is any
 12.5700 +   successor to RFC 1036.  For email messages, it is RFC 2822 [RFC2822].
 12.5701 +
 12.5702 +   Of course, any article transmitted via NNTP needs to conform to this
 12.5703 +   specification as well.
 12.5704 +
 12.5705 +   Restricting newsgroup names to UTF-8 is not a complete solution.  In
 12.5706 +   particular, when new newsgroup names are created or a user is asked
 12.5707 +   to enter a newsgroup name, some scheme of canonicalisation will need
 12.5708 +   to take place.  This specification does not attempt to define that
 12.5709 +
 12.5710 +
 12.5711 +
 12.5712 +Feather                     Standards Track                   [Page 102]
 12.5713 +
 12.5714 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5715 +
 12.5716 +
 12.5717 +   canonicalization; further work is needed in this area, in conjunction
 12.5718 +   with the article format specifications.  Until such specifications
 12.5719 +   are published, implementations SHOULD match newsgroup names octet by
 12.5720 +   octet.  It is anticipated that any approved scheme will be applied
 12.5721 +   "at the edges", and therefore octet-by-octet comparison will continue
 12.5722 +   to apply to most, if not all, uses of newsgroup names in NNTP.
 12.5723 +
 12.5724 +   In the meantime, any implementation experimenting with UTF-8
 12.5725 +   newsgroup names is strongly cautioned that a future specification may
 12.5726 +   require that those names be canonicalized when used with NNTP in a
 12.5727 +   way that is not compatible with their experiments.
 12.5728 +
 12.5729 +   Since the primary use of NNTP is with Netnews, and since newsgroup
 12.5730 +   descriptions are normally distributed through specially formatted
 12.5731 +   articles, it is recommended that the internationalisation issues
 12.5732 +   related to them be addressed in any successor to RFC 1036.
 12.5733 +
 12.5734 +11.  IANA Considerations
 12.5735 +
 12.5736 +   This specification requires IANA to keep a registry of capability
 12.5737 +   labels.  The initial contents of this registry are specified in
 12.5738 +   Section 3.3.4.  As described in Section 3.3.3, labels beginning with
 12.5739 +   X are reserved for private use, while all other names are expected to
 12.5740 +   be associated with a specification in an RFC on the standards track
 12.5741 +   or defining an IESG-approved experimental protocol.
 12.5742 +
 12.5743 +   Different entries in the registry MUST use different capability
 12.5744 +   labels.
 12.5745 +
 12.5746 +   Different entries in the registry MUST NOT use the same command name.
 12.5747 +   For this purpose, variants distinguished by a second or subsequent
 12.5748 +   keyword (e.g., "LIST HEADERS" and "LIST OVERVIEW.FMT") count as
 12.5749 +   different commands.  If there is a need for two extensions to use the
 12.5750 +   same command, a single harmonised specification MUST be registered.
 12.5751 +
 12.5752 +12.  Security Considerations
 12.5753 +
 12.5754 +   This section is meant to inform application developers, information
 12.5755 +   providers, and users of the security limitations in NNTP as described
 12.5756 +   by this document.  The discussion does not include definitive
 12.5757 +   solutions to the problems revealed, though it does make some
 12.5758 +   suggestions for reducing security risks.
 12.5759 +
 12.5760 +
 12.5761 +
 12.5762 +
 12.5763 +
 12.5764 +
 12.5765 +
 12.5766 +
 12.5767 +
 12.5768 +Feather                     Standards Track                   [Page 103]
 12.5769 +
 12.5770 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5771 +
 12.5772 +
 12.5773 +12.1.  Personal and Proprietary Information
 12.5774 +
 12.5775 +   NNTP, because it was created to distribute network news articles,
 12.5776 +   will forward whatever information is stored in those articles.
 12.5777 +   Specification of that information is outside this scope of this
 12.5778 +   document, but it is likely that some personal and/or proprietary
 12.5779 +   information is available in some of those articles.  It is very
 12.5780 +   important that designers and implementers provide informative
 12.5781 +   warnings to users so that personal and/or proprietary information in
 12.5782 +   material that is added automatically to articles (e.g., in headers)
 12.5783 +   is not disclosed inadvertently.  Additionally, effective and easily
 12.5784 +   understood mechanisms to manage the distribution of news articles
 12.5785 +   SHOULD be provided to NNTP Server administrators, so that they are
 12.5786 +   able to report with confidence the likely spread of any particular
 12.5787 +   set of news articles.
 12.5788 +
 12.5789 +12.2.  Abuse of Server Log Information
 12.5790 +
 12.5791 +   A server is in the position to save session data about a user's
 12.5792 +   requests that might identify their reading patterns or subjects of
 12.5793 +   interest.  This information is clearly confidential in nature, and
 12.5794 +   its handling can be constrained by law in certain countries.  People
 12.5795 +   using this protocol to provide data are responsible for ensuring that
 12.5796 +   such material is not distributed without the permission of any
 12.5797 +   individuals that are identifiable by the published results.
 12.5798 +
 12.5799 +12.3.  Weak Authentication and Access Control
 12.5800 +
 12.5801 +   There is no user-based or token-based authentication in the basic
 12.5802 +   NNTP specification.  Access is normally controlled by server
 12.5803 +   configuration files.  Those files specify access by using domain
 12.5804 +   names or IP addresses.  However, this specification does permit the
 12.5805 +   creation of extensions to NNTP for such purposes; one such extension
 12.5806 +   is [NNTP-AUTH].  While including such mechanisms is optional, doing
 12.5807 +   so is strongly encouraged.
 12.5808 +
 12.5809 +   Other mechanisms are also available.  For example, a proxy server
 12.5810 +   could be put in place that requires authentication before connecting
 12.5811 +   via the proxy to the NNTP server.
 12.5812 +
 12.5813 +12.4.  DNS Spoofing
 12.5814 +
 12.5815 +   Many existing NNTP implementations authorize incoming connections by
 12.5816 +   checking the IP address of that connection against the IP addresses
 12.5817 +   obtained via DNS lookups of lists of domain names given in local
 12.5818 +   configuration files.  Servers that use this type of authentication
 12.5819 +   and clients that find a server by doing a DNS lookup of the server
 12.5820 +   name rely very heavily on the Domain Name Service, and are thus
 12.5821 +
 12.5822 +
 12.5823 +
 12.5824 +Feather                     Standards Track                   [Page 104]
 12.5825 +
 12.5826 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5827 +
 12.5828 +
 12.5829 +   generally prone to security attacks based on the deliberate
 12.5830 +   misassociation of IP addresses and DNS names.  Clients and servers
 12.5831 +   need to be cautious in assuming the continuing validity of an IP
 12.5832 +   number/DNS name association.
 12.5833 +
 12.5834 +   In particular, NNTP clients and servers SHOULD rely on their name
 12.5835 +   resolver for confirmation of an IP number/DNS name association,
 12.5836 +   rather than cache the result of previous host name lookups.  Many
 12.5837 +   platforms already can cache host name lookups locally when
 12.5838 +   appropriate, and they SHOULD be configured to do so.  It is proper
 12.5839 +   for these lookups to be cached, however, only when the TTL (Time To
 12.5840 +   Live) information reported by the name server makes it likely that
 12.5841 +   the cached information will remain useful.
 12.5842 +
 12.5843 +   If NNTP clients or servers cache the results of host name lookups in
 12.5844 +   order to achieve a performance improvement, they MUST observe the TTL
 12.5845 +   information reported by DNS.  If NNTP clients or servers do not
 12.5846 +   observe this rule, they could be spoofed when a previously accessed
 12.5847 +   server's IP address changes.  As network renumbering is expected to
 12.5848 +   become increasingly common, the possibility of this form of attack
 12.5849 +   will increase.  Observing this requirement thus reduces this
 12.5850 +   potential security vulnerability.
 12.5851 +
 12.5852 +   This requirement also improves the load-balancing behaviour of
 12.5853 +   clients for replicated servers using the same DNS name and reduces
 12.5854 +   the likelihood of a user's experiencing failure in accessing sites
 12.5855 +   that use that strategy.
 12.5856 +
 12.5857 +12.5.  UTF-8 Issues
 12.5858 +
 12.5859 +   UTF-8 [RFC3629] permits only certain sequences of octets and
 12.5860 +   designates others as either malformed or "illegal".  The Unicode
 12.5861 +   standard identifies a number of security issues related to illegal
 12.5862 +   sequences and forbids their generation by conforming implementations.
 12.5863 +
 12.5864 +   Implementations of this specification MUST NOT generate malformed or
 12.5865 +   illegal sequences and SHOULD detect them and take some appropriate
 12.5866 +   action.  This could include the following:
 12.5867 +
 12.5868 +   o  Generating a 501 response code.
 12.5869 +
 12.5870 +   o  Replacing such sequences by the sequence %xEF.BF.BD, which encodes
 12.5871 +      the "replacement character" U+FFFD.
 12.5872 +
 12.5873 +   o  Closing the connection.
 12.5874 +
 12.5875 +   o  Replacing such sequences by a "guessed" valid sequence (based on
 12.5876 +      properties of the UTF-8 encoding).
 12.5877 +
 12.5878 +
 12.5879 +
 12.5880 +Feather                     Standards Track                   [Page 105]
 12.5881 +
 12.5882 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5883 +
 12.5884 +
 12.5885 +   In the last case, the implementation MUST ensure that any replacement
 12.5886 +   cannot be used to bypass validity or security checks.  For example,
 12.5887 +   the illegal sequence %xC0.A0 is an over-long encoding for space
 12.5888 +   (%x20).  If it is replaced by the correct encoding in a command line,
 12.5889 +   this needs to happen before the command line is parsed into
 12.5890 +   individual arguments.  If the replacement came after parsing, it
 12.5891 +   would be possible to generate an argument with an embedded space,
 12.5892 +   which is forbidden.  Use of the "replacement character" does not have
 12.5893 +   this problem, since it is permitted wherever non-US-ASCII characters
 12.5894 +   are.  Implementations SHOULD use one of the first two solutions where
 12.5895 +   the general structure of the NNTP stream remains intact and SHOULD
 12.5896 +   close the connection if it is no longer possible to parse it
 12.5897 +   sensibly.
 12.5898 +
 12.5899 +12.6.  Caching of Capability Lists
 12.5900 +
 12.5901 +   The CAPABILITIES command provides a capability list, which is
 12.5902 +   information about the current capabilities of the server.  Whenever
 12.5903 +   there is a relevant change to the server state, the results of this
 12.5904 +   command are required to change accordingly.
 12.5905 +
 12.5906 +   In most situations, the capabilities list in a given server state
 12.5907 +   will not change from session to session; for example, a given
 12.5908 +   extension will be installed permanently on a server.  Some clients
 12.5909 +   may therefore wish to remember which extensions a server supports to
 12.5910 +   avoid the delay of an additional command and response, particularly
 12.5911 +   if they open multiple connections in the same session.
 12.5912 +
 12.5913 +   However, information about extensions related to security and privacy
 12.5914 +   MUST NOT be cached, since this could allow a variety of attacks.
 12.5915 +
 12.5916 +   For example, consider a server that permits the use of cleartext
 12.5917 +   passwords on links that are encrypted but not otherwise:
 12.5918 +
 12.5919 +      [Initial connection set-up completed.]
 12.5920 +      [S] 200 NNTP Service Ready, posting permitted
 12.5921 +      [C] CAPABILITIES
 12.5922 +      [S] 101 Capability list:
 12.5923 +      [S] VERSION 2
 12.5924 +      [S] READER
 12.5925 +      [S] NEWNEWS
 12.5926 +      [S] POST
 12.5927 +      [S] XENCRYPT
 12.5928 +      [S] LIST ACTIVE NEWSGROUPS
 12.5929 +      [S] .
 12.5930 +      [C] XENCRYPT
 12.5931 +      [Client and server negotiate encryption on the link]
 12.5932 +      [S] 283 Encrypted link established
 12.5933 +
 12.5934 +
 12.5935 +
 12.5936 +Feather                     Standards Track                   [Page 106]
 12.5937 +
 12.5938 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5939 +
 12.5940 +
 12.5941 +      [C] CAPABILITIES
 12.5942 +      [S] 101 Capability list:
 12.5943 +      [S] VERSION 2
 12.5944 +      [S] READER
 12.5945 +      [S] NEWNEWS
 12.5946 +      [S] POST
 12.5947 +      [S] XSECRET
 12.5948 +      [S] LIST ACTIVE NEWSGROUPS
 12.5949 +      [S] .
 12.5950 +      [C] XSECRET fred flintstone
 12.5951 +      [S] 290 Password for fred accepted
 12.5952 +
 12.5953 +   If the client caches the last capabilities list, then on the next
 12.5954 +   session it will attempt to use XSECRET on an unencrypted link:
 12.5955 +
 12.5956 +      [Initial connection set-up completed.]
 12.5957 +      [S] 200 NNTP Service Ready, posting permitted
 12.5958 +      [C] XSECRET fred flintstone
 12.5959 +      [S] 483 Only permitted on secure links
 12.5960 +
 12.5961 +   This exposes the password to any eavesdropper.  While the primary
 12.5962 +   cause of this is passing a secret without first checking the security
 12.5963 +   of the link, caching of capability lists can increase the risk.
 12.5964 +
 12.5965 +   Any security extension should include requirements to check the
 12.5966 +   security state of the link in a manner appropriate to that extension.
 12.5967 +
 12.5968 +   Caching should normally only be considered for anonymous clients that
 12.5969 +   do not use any security or privacy extensions and for which the time
 12.5970 +   required for an additional command and response is a noticeable
 12.5971 +   issue.
 12.5972 +
 12.5973 +13.  Acknowledgements
 12.5974 +
 12.5975 +   This document is the result of much effort by the present and past
 12.5976 +   members of the NNTP Working Group, chaired by Russ Allbery and Ned
 12.5977 +   Freed.  It could not have been produced without them.
 12.5978 +
 12.5979 +   The author acknowledges the original authors of NNTP as documented in
 12.5980 +   RFC 977 [RFC977]: Brian Kantor and Phil Lapsey.
 12.5981 +
 12.5982 +   The author gratefully acknowledges the following:
 12.5983 +
 12.5984 +   o  The work of the NNTP committee chaired by Eliot Lear.  The
 12.5985 +      organization of this document was influenced by the last available
 12.5986 +      version from this working group.  A special thanks to Eliot for
 12.5987 +      generously providing the original machine-readable sources for
 12.5988 +      that document.
 12.5989 +
 12.5990 +
 12.5991 +
 12.5992 +Feather                     Standards Track                   [Page 107]
 12.5993 +
 12.5994 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.5995 +
 12.5996 +
 12.5997 +   o  The work of the DRUMS working group, specifically RFC 1869
 12.5998 +      [RFC1869], that drove the original thinking that led to the
 12.5999 +      CAPABILITIES command and the extensions mechanism detailed in this
 12.6000 +      document.
 12.6001 +
 12.6002 +   o  The authors of RFC 2616 [RFC2616] for providing specific and
 12.6003 +      relevant examples of security issues that should be considered for
 12.6004 +      HTTP.  Since many of the same considerations exist for NNTP, those
 12.6005 +      examples that are relevant have been included here with some minor
 12.6006 +      rewrites.
 12.6007 +
 12.6008 +   o  The comments and additional information provided by the following
 12.6009 +      individuals in preparing one or more of the progenitors of this
 12.6010 +      document:
 12.6011 +
 12.6012 +         Russ Allbery <rra@stanford.edu>
 12.6013 +         Wayne Davison <davison@armory.com>
 12.6014 +         Chris Lewis <clewis@bnr.ca>
 12.6015 +         Tom Limoncelli <tal@mars.superlink.net>
 12.6016 +         Eric Schnoebelen <eric@egsner.cirr.com>
 12.6017 +         Rich Salz <rsalz@osf.org>
 12.6018 +
 12.6019 +   This work was motivated by the work of various news reader authors
 12.6020 +   and news server authors, including those listed below:
 12.6021 +
 12.6022 +   Rick Adams
 12.6023 +      Original author of the NNTP extensions to the RN news reader and
 12.6024 +      last maintainer of Bnews.
 12.6025 +
 12.6026 +   Stan Barber
 12.6027 +      Original author of the NNTP extensions to the news readers that
 12.6028 +      are part of Bnews.
 12.6029 +
 12.6030 +   Geoff Collyer
 12.6031 +      Original author of the OVERVIEW database proposal and one of the
 12.6032 +      original authors of CNEWS.
 12.6033 +
 12.6034 +   Dan Curry
 12.6035 +      Original author of the xvnews news reader.
 12.6036 +
 12.6037 +   Wayne Davison
 12.6038 +      Author of the first threading extensions to the RN news reader
 12.6039 +      (commonly called TRN).
 12.6040 +
 12.6041 +   Geoff Huston
 12.6042 +      Original author of ANU NEWS.
 12.6043 +
 12.6044 +
 12.6045 +
 12.6046 +
 12.6047 +
 12.6048 +Feather                     Standards Track                   [Page 108]
 12.6049 +
 12.6050 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6051 +
 12.6052 +
 12.6053 +   Phil Lapsey
 12.6054 +      Original author of the UNIX reference implementation for NNTP.
 12.6055 +
 12.6056 +   Iain Lea
 12.6057 +      Original maintainer of the TIN news reader.
 12.6058 +
 12.6059 +   Chris Lewis
 12.6060 +      First known implementer of the AUTHINFO GENERIC extension.
 12.6061 +
 12.6062 +   Rich Salz
 12.6063 +      Original author of INN.
 12.6064 +
 12.6065 +   Henry Spencer
 12.6066 +      One of the original authors of CNEWS.
 12.6067 +
 12.6068 +   Kim Storm
 12.6069 +      Original author of the NN news reader.
 12.6070 +
 12.6071 +   Other people who contributed to this document include:
 12.6072 +
 12.6073 +      Matthias Andree
 12.6074 +      Greg Andruk
 12.6075 +      Daniel Barclay
 12.6076 +      Maurizio Codogno
 12.6077 +      Mark Crispin
 12.6078 +      Andrew Gierth
 12.6079 +      Juergen Helbing
 12.6080 +      Scott Hollenbeck
 12.6081 +      Urs Janssen
 12.6082 +      Charles Lindsey
 12.6083 +      Ade Lovett
 12.6084 +      David Magda
 12.6085 +      Ken Murchison
 12.6086 +      Francois Petillon
 12.6087 +      Peter Robinson
 12.6088 +      Rob Siemborski
 12.6089 +      Howard Swinehart
 12.6090 +      Ruud van Tol
 12.6091 +      Jeffrey Vinocur
 12.6092 +      Erik Warmelink
 12.6093 +
 12.6094 +   The author thanks them all and apologises to anyone omitted.
 12.6095 +
 12.6096 +   Finally, the present author gratefully acknowledges the vast amount
 12.6097 +   of work put into previous versions by the previous author:
 12.6098 +
 12.6099 +      Stan Barber <sob@academ.com>
 12.6100 +
 12.6101 +
 12.6102 +
 12.6103 +
 12.6104 +Feather                     Standards Track                   [Page 109]
 12.6105 +
 12.6106 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6107 +
 12.6108 +
 12.6109 +14.  References
 12.6110 +
 12.6111 +14.1.  Normative References
 12.6112 +
 12.6113 +   [ANSI1986]    American National Standards Institute, "Coded Character
 12.6114 +                 Set - 7-bit American Standard Code for Information
 12.6115 +                 Interchange", ANSI X3.4, 1986.
 12.6116 +
 12.6117 +   [RFC977]      Kantor, B. and P. Lapsley, "Network News Transfer
 12.6118 +                 Protocol", RFC 977, February 1986.
 12.6119 +
 12.6120 +   [RFC2045]     Freed, N. and N. Borenstein, "Multipurpose Internet
 12.6121 +                 Mail Extensions (MIME) Part One: Format of Internet
 12.6122 +                 Message Bodies", RFC 2045, November 1996.
 12.6123 +
 12.6124 +   [RFC2047]     Moore, K., "MIME (Multipurpose Internet Mail
 12.6125 +                 Extensions) Part Three: Message Header Extensions for
 12.6126 +                 Non-ASCII Text", RFC 2047, November 1996.
 12.6127 +
 12.6128 +   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
 12.6129 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
 12.6130 +
 12.6131 +   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
 12.6132 +                 10646", STD 63, RFC 3629, November 2003.
 12.6133 +
 12.6134 +   [RFC4234]     Crocker, D., Ed. and P. Overell, "Augmented BNF for
 12.6135 +                 Syntax Specifications: ABNF", RFC 4234, October 2005.
 12.6136 +
 12.6137 +   [RFC4648]     Josefsson, S., "The Base16, Base32, and Base64 Data
 12.6138 +                 Encodings", RFC 4648, October 2006.
 12.6139 +
 12.6140 +   [TF.686-1]    International Telecommunications Union - Radio,
 12.6141 +                 "Glossary, ITU-R Recommendation TF.686-1",
 12.6142 +                 ITU-R Recommendation TF.686-1, October 1997.
 12.6143 +
 12.6144 +14.2.  Informative References
 12.6145 +
 12.6146 +   [NNTP-AUTH]   Vinocur, J., Murchison, K., and C. Newman, "Network
 12.6147 +                 News Transfer Protocol (NNTP) Extension for
 12.6148 +                 Authentication",
 12.6149 +                 RFC 4643, October 2006.
 12.6150 +
 12.6151 +   [NNTP-STREAM] Vinocur, J. and K. Murchison, "Network News Transfer
 12.6152 +                 Protocol (NNTP) Extension for Streaming Feeds",
 12.6153 +                 RFC 4644, October 2006.
 12.6154 +
 12.6155 +
 12.6156 +
 12.6157 +
 12.6158 +
 12.6159 +
 12.6160 +Feather                     Standards Track                   [Page 110]
 12.6161 +
 12.6162 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6163 +
 12.6164 +
 12.6165 +   [NNTP-TLS]    Murchison, K., Vinocur, J., and C. Newman, "Using
 12.6166 +                 Transport Layer Security (TLS) with Network News
 12.6167 +                 Transfer Protocol (NNTP)", RFC 4642, October 2006.
 12.6168 +
 12.6169 +   [RFC1036]     Horton, M. and R. Adams, "Standard for interchange of
 12.6170 +                 USENET messages", RFC 1036, December 1987.
 12.6171 +
 12.6172 +   [RFC1305]     Mills, D., "Network Time Protocol (Version 3)
 12.6173 +                 Specification, Implementation and Analysis", RFC 1305,
 12.6174 +                 March 1992.
 12.6175 +
 12.6176 +   [RFC1869]     Klensin, J., Freed, N., Rose, M., Stefferud, E., and D.
 12.6177 +                 Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
 12.6178 +                 November 1995.
 12.6179 +
 12.6180 +   [RFC2616]     Fielding,  R., Gettys, J., Mogul, J., Frystyk, H.,
 12.6181 +                 Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
 12.6182 +                 Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
 12.6183 +
 12.6184 +   [RFC2629]     Rose, M., "Writing I-Ds and RFCs using XML", RFC 2629,
 12.6185 +                 June 1999.
 12.6186 +
 12.6187 +   [RFC2822]     Resnick, P., "Internet Message Format", RFC 2822, April
 12.6188 +                 2001.
 12.6189 +
 12.6190 +   [RFC2980]     Barber, S., "Common NNTP Extensions", RFC 2980, October
 12.6191 +                 2000.
 12.6192 +
 12.6193 +   [ROBE1995]    Robertson, R., "FAQ: Overview database / NOV General
 12.6194 +                 Information", January 1995.
 12.6195 +
 12.6196 +                 There is no definitive copy of this document known to
 12.6197 +                 the author.  It was previously posted as the Usenet
 12.6198 +                 article <news:nov-faq-1-930909720@agate.Berkeley.EDU>
 12.6199 +
 12.6200 +   [SALZ1992]    Salz, R., "Manual Page for wildmat(3) from the INN 1.4
 12.6201 +                 distribution, Revision 1.10", April 1992.
 12.6202 +
 12.6203 +                 There is no definitive copy of this document known to
 12.6204 +                 the author.
 12.6205 +
 12.6206 +
 12.6207 +
 12.6208 +
 12.6209 +
 12.6210 +
 12.6211 +
 12.6212 +
 12.6213 +
 12.6214 +
 12.6215 +
 12.6216 +Feather                     Standards Track                   [Page 111]
 12.6217 +
 12.6218 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6219 +
 12.6220 +
 12.6221 +Appendix A.  Interaction with Other Specifications
 12.6222 +
 12.6223 +   NNTP is most often used for transferring articles that conform to
 12.6224 +   RFC 1036 [RFC1036] (such articles are called "Netnews articles"
 12.6225 +   here).  It is also sometimes used for transferring email messages
 12.6226 +   that conform to RFC 2822 [RFC2822] (such articles are called "email
 12.6227 +   articles" here).  In this situation, articles must conform both to
 12.6228 +   this specification and to that other one; this appendix describes
 12.6229 +   some relevant issues.
 12.6230 +
 12.6231 +A.1.  Header Folding
 12.6232 +
 12.6233 +   NNTP allows a header line to be folded (by inserting a CRLF pair)
 12.6234 +   before any space or TAB character.
 12.6235 +
 12.6236 +   Both email and Netnews articles are required to have at least one
 12.6237 +   octet other than space or TAB on each header line.  Thus, folding can
 12.6238 +   only happen at one point in each sequence of consecutive spaces or
 12.6239 +   TABs.  Netnews articles are further required to have the header name,
 12.6240 +   colon, and following space all on the first line; folding may only
 12.6241 +   happen beyond that space.  Finally, some non-conforming software will
 12.6242 +   remove trailing spaces and TABs from a line.  Therefore, it might be
 12.6243 +   inadvisable to fold a header after a space or TAB.
 12.6244 +
 12.6245 +   For maximum safety, header lines SHOULD conform to the following
 12.6246 +   syntax rather than to that in Section 9.7.
 12.6247 +
 12.6248 +
 12.6249 +     header = header-name ":" SP [header-content] CRLF
 12.6250 +     header-content = [WS] token *( [CRLF] WS token )
 12.6251 +
 12.6252 +A.2.  Message-IDs
 12.6253 +
 12.6254 +   Every article handled by an NNTP server MUST have a unique
 12.6255 +   message-id.  For the purposes of this specification, a message-id is
 12.6256 +   an arbitrary opaque string that merely needs to meet certain
 12.6257 +   syntactic requirements and is just a way to refer to the article.
 12.6258 +
 12.6259 +   Because there is a significant risk that old articles will be
 12.6260 +   reinjected into the global Usenet system, RFC 1036 [RFC1036] requires
 12.6261 +   that message-ids are globally unique for all time.
 12.6262 +
 12.6263 +   This specification states that message-ids are the same if and only
 12.6264 +   if they consist of the same sequence of octets.  Other specifications
 12.6265 +   may define two different sequences as being equal because they are
 12.6266 +   putting an interpretation on particular characters.  RFC 2822
 12.6267 +   [RFC2822] has a concept of "quoted" and "escaped" characters.  It
 12.6268 +   therefore considers the three message-ids:
 12.6269 +
 12.6270 +
 12.6271 +
 12.6272 +Feather                     Standards Track                   [Page 112]
 12.6273 +
 12.6274 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6275 +
 12.6276 +
 12.6277 +      <ab.cd@example.com>
 12.6278 +      <"ab.cd"@example.com>
 12.6279 +      <"ab.\cd"@example.com>
 12.6280 +
 12.6281 +   as being identical.  Therefore, an NNTP implementation handing email
 12.6282 +   articles must ensure that only one of these three appears in the
 12.6283 +   protocol and that the other two are converted to it as and when
 12.6284 +   necessary, such as when a client checks the results of a NEWNEWS
 12.6285 +   command against an internal database of message-ids.  Note that
 12.6286 +   RFC 1036 [RFC1036] never treats two different strings as being
 12.6287 +   identical.  Its successor (as of the time of writing) restricts the
 12.6288 +   syntax of message-ids so that, whenever RFC 2822 would treat two
 12.6289 +   strings as equivalent, only one of them is valid (in the above
 12.6290 +   example, only the first string is valid).
 12.6291 +
 12.6292 +   This specification does not describe how the message-id of an article
 12.6293 +   is determined; it may be deduced from the contents of the article or
 12.6294 +   derived from some external source.  If the server is also conforming
 12.6295 +   to another specification that contains a definition of message-id
 12.6296 +   compatible with this one, the server SHOULD use those message-ids.  A
 12.6297 +   common approach, and one that SHOULD be used for email and Netnews
 12.6298 +   articles, is to extract the message-id from the contents of a header
 12.6299 +   with name "Message-ID".  This may not be as simple as copying the
 12.6300 +   entire header contents; it may be necessary to strip off comments and
 12.6301 +   undo quoting, or to reduce "equivalent" message-ids to a canonical
 12.6302 +   form.
 12.6303 +
 12.6304 +   If an article is obtained through the IHAVE command, there will be a
 12.6305 +   message-id provided with the command.  The server MAY either use it
 12.6306 +   or determine one from the article contents.  However, whichever it
 12.6307 +   does, it SHOULD ensure that, if the IHAVE command is repeated with
 12.6308 +   the same argument and article, it will be recognized as a duplicate.
 12.6309 +
 12.6310 +   If an article does not contain a message-id that the server can
 12.6311 +   identify, it MUST synthesize one.  This could, for example, be a
 12.6312 +   simple sequence number or be based on the date and time when the
 12.6313 +   article arrived.  When email or Netnews articles are handled, a
 12.6314 +   Message-ID header SHOULD be added to ensure global consistency and
 12.6315 +   uniqueness.
 12.6316 +
 12.6317 +   Note that, because the message-id might not have been derived from
 12.6318 +   the Message-ID header in the article, the following example is
 12.6319 +   legitimate (though unusual):
 12.6320 +
 12.6321 +
 12.6322 +
 12.6323 +
 12.6324 +
 12.6325 +
 12.6326 +
 12.6327 +
 12.6328 +Feather                     Standards Track                   [Page 113]
 12.6329 +
 12.6330 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6331 +
 12.6332 +
 12.6333 +      [C] HEAD <45223423@example.com>
 12.6334 +      [S] 221 0 <45223423@example.com>
 12.6335 +      [S] Path: pathost!demo!whitehouse!not-for-mail
 12.6336 +      [S] Message-ID: <1234@example.net>
 12.6337 +      [S] From: "Demo User" <nobody@example.net>
 12.6338 +      [S] Newsgroups: misc.test
 12.6339 +      [S] Subject: I am just a test article
 12.6340 +      [S] Date: 6 Oct 1998 04:38:40 -0500
 12.6341 +      [S] Organization: An Example Net, Uncertain, Texas
 12.6342 +      [S] .
 12.6343 +
 12.6344 +A.3.  Article Posting
 12.6345 +
 12.6346 +   As far as NNTP is concerned, the POST and IHAVE commands provide the
 12.6347 +   same basic facilities in a slightly different way.  However, they
 12.6348 +   have rather different intentions.
 12.6349 +
 12.6350 +   The IHAVE command is intended for transmitting conforming articles
 12.6351 +   between a system of NNTP servers, with all articles perhaps also
 12.6352 +   conforming to another specification (e.g., all articles are Netnews
 12.6353 +   articles).  It is expected that the client will already have done any
 12.6354 +   necessary validation (or that it has in turn obtained the article
 12.6355 +   from a third party that has done so); therefore, the contents SHOULD
 12.6356 +   be left unchanged.
 12.6357 +
 12.6358 +   In contrast, the POST command is intended for use when an end-user is
 12.6359 +   injecting a newly created article into a such a system.  The article
 12.6360 +   being transferred might not be a conforming email or Netnews article,
 12.6361 +   and the server is expected to validate it and, if necessary, to
 12.6362 +   convert it to the right form for onward distribution.  This is often
 12.6363 +   done by a separate piece of software on the server installation; if
 12.6364 +   so, the NNTP server SHOULD pass the incoming article to that software
 12.6365 +   unaltered, making no attempt to filter characters, to fold or limit
 12.6366 +   lines, or to process the incoming text otherwise.
 12.6367 +
 12.6368 +   The POST command can fail in various ways, and clients should be
 12.6369 +   prepared to re-send an article.  When doing so, however, it is often
 12.6370 +   important to ensure (as far as possible) that the same message-id is
 12.6371 +   allocated to both attempts so that the server, or other servers, can
 12.6372 +   recognize the two articles as duplicates.  In the case of email or
 12.6373 +   Netnews articles, therefore, the posted article SHOULD contain a
 12.6374 +   header with the name "Message-ID", and the contents of this header
 12.6375 +   SHOULD be identical on each attempt.  The server SHOULD ensure that
 12.6376 +   two POSTed articles with the same contents for this header are
 12.6377 +   recognized as identical and that the same message-id is allocated,
 12.6378 +   whether or not those contents are suitable for use as the message-id.
 12.6379 +
 12.6380 +
 12.6381 +
 12.6382 +
 12.6383 +
 12.6384 +Feather                     Standards Track                   [Page 114]
 12.6385 +
 12.6386 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6387 +
 12.6388 +
 12.6389 +Appendix B.  Summary of Commands
 12.6390 +
 12.6391 +   This section contains a list of every command defined in this
 12.6392 +   document, ordered by command name and by indicating capability.
 12.6393 +
 12.6394 +                         Ordered by command name:
 12.6395 +
 12.6396 +       +-------------------+-----------------------+---------------+
 12.6397 +       | Command           | Indicating capability | Definition    |
 12.6398 +       +-------------------+-----------------------+---------------+
 12.6399 +       | ARTICLE           | READER                | Section 6.2.1 |
 12.6400 +       | BODY              | READER                | Section 6.2.3 |
 12.6401 +       | CAPABILITIES      | mandatory             | Section 5.2   |
 12.6402 +       | DATE              | READER                | Section 7.1   |
 12.6403 +       | GROUP             | READER                | Section 6.1.1 |
 12.6404 +       | HDR               | HDR                   | Section 8.5   |
 12.6405 +       | HEAD              | mandatory             | Section 6.2.2 |
 12.6406 +       | HELP              | mandatory             | Section 7.2   |
 12.6407 +       | IHAVE             | IHAVE                 | Section 6.3.2 |
 12.6408 +       | LAST              | READER                | Section 6.1.3 |
 12.6409 +       | LIST              | LIST                  | Section 7.6.1 |
 12.6410 +       | LIST ACTIVE.TIMES | LIST                  | Section 7.6.4 |
 12.6411 +       | LIST ACTIVE       | LIST                  | Section 7.6.3 |
 12.6412 +       | LIST DISTRIB.PATS | LIST                  | Section 7.6.5 |
 12.6413 +       | LIST HEADERS      | HDR                   | Section 8.6   |
 12.6414 +       | LIST NEWSGROUPS   | LIST                  | Section 7.6.6 |
 12.6415 +       | LIST OVERVIEW.FMT | OVER                  | Section 8.4   |
 12.6416 +       | LISTGROUP         | READER                | Section 6.1.2 |
 12.6417 +       | MODE READER       | MODE-READER           | Section 5.3   |
 12.6418 +       | NEWGROUPS         | READER                | Section 7.3   |
 12.6419 +       | NEWNEWS           | NEWNEWS               | Section 7.4   |
 12.6420 +       | NEXT              | READER                | Section 6.1.4 |
 12.6421 +       | OVER              | OVER                  | Section 8.3   |
 12.6422 +       | POST              | POST                  | Section 6.3.1 |
 12.6423 +       | QUIT              | mandatory             | Section 5.4   |
 12.6424 +       | STAT              | mandatory             | Section 6.2.4 |
 12.6425 +       +-------------------+-----------------------+---------------+
 12.6426 +
 12.6427 +
 12.6428 +
 12.6429 +
 12.6430 +
 12.6431 +
 12.6432 +
 12.6433 +
 12.6434 +
 12.6435 +
 12.6436 +
 12.6437 +
 12.6438 +
 12.6439 +
 12.6440 +Feather                     Standards Track                   [Page 115]
 12.6441 +
 12.6442 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6443 +
 12.6444 +
 12.6445 +                     Ordered by indicating capability:
 12.6446 +
 12.6447 +       +-------------------+-----------------------+---------------+
 12.6448 +       | Command           | Indicating capability | Definition    |
 12.6449 +       +-------------------+-----------------------+---------------+
 12.6450 +       | CAPABILITIES      | mandatory             | Section 5.2   |
 12.6451 +       | HEAD              | mandatory             | Section 6.2.2 |
 12.6452 +       | HELP              | mandatory             | Section 7.2   |
 12.6453 +       | QUIT              | mandatory             | Section 5.4   |
 12.6454 +       | STAT              | mandatory             | Section 6.2.4 |
 12.6455 +       | HDR               | HDR                   | Section 8.5   |
 12.6456 +       | LIST HEADERS      | HDR                   | Section 8.6   |
 12.6457 +       | IHAVE             | IHAVE                 | Section 6.3.2 |
 12.6458 +       | LIST              | LIST                  | Section 7.6.1 |
 12.6459 +       | LIST ACTIVE       | LIST                  | Section 7.6.3 |
 12.6460 +       | LIST ACTIVE.TIMES | LIST                  | Section 7.6.4 |
 12.6461 +       | LIST DISTRIB.PATS | LIST                  | Section 7.6.5 |
 12.6462 +       | LIST NEWSGROUPS   | LIST                  | Section 7.6.6 |
 12.6463 +       | MODE READER       | MODE-READER           | Section 5.3   |
 12.6464 +       | NEWNEWS           | NEWNEWS               | Section 7.4   |
 12.6465 +       | OVER              | OVER                  | Section 8.3   |
 12.6466 +       | LIST OVERVIEW.FMT | OVER                  | Section 8.4   |
 12.6467 +       | POST              | POST                  | Section 6.3.1 |
 12.6468 +       | ARTICLE           | READER                | Section 6.2.1 |
 12.6469 +       | BODY              | READER                | Section 6.2.3 |
 12.6470 +       | DATE              | READER                | Section 7.1   |
 12.6471 +       | GROUP             | READER                | Section 6.1.1 |
 12.6472 +       | LAST              | READER                | Section 6.1.3 |
 12.6473 +       | LISTGROUP         | READER                | Section 6.1.2 |
 12.6474 +       | NEWGROUPS         | READER                | Section 7.3   |
 12.6475 +       | NEXT              | READER                | Section 6.1.4 |
 12.6476 +       +-------------------+-----------------------+---------------+
 12.6477 +
 12.6478 +
 12.6479 +
 12.6480 +
 12.6481 +
 12.6482 +
 12.6483 +
 12.6484 +
 12.6485 +
 12.6486 +
 12.6487 +
 12.6488 +
 12.6489 +
 12.6490 +
 12.6491 +
 12.6492 +
 12.6493 +
 12.6494 +
 12.6495 +
 12.6496 +Feather                     Standards Track                   [Page 116]
 12.6497 +
 12.6498 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6499 +
 12.6500 +
 12.6501 +Appendix C.  Summary of Response Codes
 12.6502 +
 12.6503 +   This section contains a list of every response code defined in this
 12.6504 +   document and indicates whether it is multi-line, which commands can
 12.6505 +   generate it, what arguments it has, and what its meaning is.
 12.6506 +
 12.6507 +   Response code 100 (multi-line)
 12.6508 +      Generated by: HELP
 12.6509 +      Meaning: help text follows.
 12.6510 +
 12.6511 +   Response code 101 (multi-line)
 12.6512 +      Generated by: CAPABILITIES
 12.6513 +      Meaning: capabilities list follows.
 12.6514 +
 12.6515 +   Response code 111
 12.6516 +      Generated by: DATE
 12.6517 +      1 argument: yyyymmddhhmmss
 12.6518 +      Meaning: server date and time.
 12.6519 +
 12.6520 +   Response code 200
 12.6521 +      Generated by: initial connection, MODE READER
 12.6522 +      Meaning: service available, posting allowed.
 12.6523 +
 12.6524 +   Response code 201
 12.6525 +      Generated by: initial connection, MODE READER
 12.6526 +      Meaning: service available, posting prohibited.
 12.6527 +
 12.6528 +   Response code 205
 12.6529 +      Generated by: QUIT
 12.6530 +      Meaning: connection closing (the server immediately closes the
 12.6531 +      connection).
 12.6532 +
 12.6533 +   Response code 211
 12.6534 +      The 211 response code has two completely different forms,
 12.6535 +      depending on which command generated it:
 12.6536 +
 12.6537 +         (not multi-line)
 12.6538 +         Generated by: GROUP
 12.6539 +         4 arguments: number low high group
 12.6540 +         Meaning: group selected.
 12.6541 +
 12.6542 +         (multi-line)
 12.6543 +         Generated by: LISTGROUP
 12.6544 +         4 arguments: number low high group
 12.6545 +         Meaning: article numbers follow.
 12.6546 +
 12.6547 +
 12.6548 +
 12.6549 +
 12.6550 +
 12.6551 +
 12.6552 +Feather                     Standards Track                   [Page 117]
 12.6553 +
 12.6554 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6555 +
 12.6556 +
 12.6557 +   Response code 215 (multi-line)
 12.6558 +      Generated by: LIST
 12.6559 +      Meaning: information follows.
 12.6560 +
 12.6561 +   Response code 220 (multi-line)
 12.6562 +      Generated by: ARTICLE
 12.6563 +      2 arguments: n message-id
 12.6564 +      Meaning: article follows.
 12.6565 +
 12.6566 +   Response code 221 (multi-line)
 12.6567 +      Generated by: HEAD
 12.6568 +      2 arguments: n message-id
 12.6569 +      Meaning: article headers follow.
 12.6570 +
 12.6571 +   Response code 222 (multi-line)
 12.6572 +      Generated by: BODY
 12.6573 +      2 arguments: n message-id
 12.6574 +      Meaning: article body follows.
 12.6575 +
 12.6576 +   Response code 223
 12.6577 +      Generated by: LAST, NEXT, STAT
 12.6578 +      2 arguments: n message-id
 12.6579 +      Meaning: article exists and selected.
 12.6580 +
 12.6581 +   Response code 224 (multi-line)
 12.6582 +      Generated by: OVER
 12.6583 +      Meaning: overview information follows.
 12.6584 +
 12.6585 +   Response code 225 (multi-line)
 12.6586 +      Generated by: HDR
 12.6587 +      Meaning: headers follow.
 12.6588 +
 12.6589 +   Response code 230 (multi-line)
 12.6590 +      Generated by: NEWNEWS
 12.6591 +      Meaning: list of new articles follows.
 12.6592 +
 12.6593 +   Response code 231 (multi-line)
 12.6594 +      Generated by: NEWGROUPS
 12.6595 +      Meaning: list of new newsgroups follows.
 12.6596 +
 12.6597 +   Response code 235
 12.6598 +      Generated by: IHAVE (second stage)
 12.6599 +      Meaning: article transferred OK.
 12.6600 +
 12.6601 +   Response code 240
 12.6602 +      Generated by: POST (second stage)
 12.6603 +      Meaning: article received OK.
 12.6604 +
 12.6605 +
 12.6606 +
 12.6607 +
 12.6608 +Feather                     Standards Track                   [Page 118]
 12.6609 +
 12.6610 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6611 +
 12.6612 +
 12.6613 +   Response code 335
 12.6614 +      Generated by: IHAVE (first stage)
 12.6615 +      Meaning: send article to be transferred.
 12.6616 +
 12.6617 +   Response code 340
 12.6618 +      Generated by: POST (first stage)
 12.6619 +      Meaning: send article to be posted.
 12.6620 +
 12.6621 +   Response code 400
 12.6622 +      Generic response and generated by initial connection
 12.6623 +      Meaning: service not available or no longer available (the server
 12.6624 +      immediately closes the connection).
 12.6625 +
 12.6626 +   Response code 401
 12.6627 +      Generic response
 12.6628 +      1 argument: capability-label
 12.6629 +      Meaning: the server is in the wrong mode; the indicated capability
 12.6630 +      should be used to change the mode.
 12.6631 +
 12.6632 +   Response code 403
 12.6633 +      Generic response
 12.6634 +      Meaning: internal fault or problem preventing action being taken.
 12.6635 +
 12.6636 +   Response code 411
 12.6637 +      Generated by: GROUP, LISTGROUP
 12.6638 +      Meaning: no such newsgroup.
 12.6639 +
 12.6640 +   Response code 412
 12.6641 +      Generated by: ARTICLE, BODY, GROUP, HDR, HEAD, LAST, LISTGROUP,
 12.6642 +      NEXT, OVER, STAT
 12.6643 +      Meaning: no newsgroup selected.
 12.6644 +
 12.6645 +   Response code 420
 12.6646 +      Generated by: ARTICLE, BODY, HDR, HEAD, LAST, NEXT, OVER, STAT
 12.6647 +      Meaning: current article number is invalid.
 12.6648 +
 12.6649 +   Response code 421
 12.6650 +      Generated by: NEXT
 12.6651 +      Meaning: no next article in this group.
 12.6652 +
 12.6653 +   Response code 422
 12.6654 +      Generated by: LAST
 12.6655 +      Meaning: no previous article in this group.
 12.6656 +
 12.6657 +   Response code 423
 12.6658 +      Generated by: ARTICLE, BODY, HDR, HEAD, OVER, STAT
 12.6659 +      Meaning: no article with that number or in that range.
 12.6660 +
 12.6661 +
 12.6662 +
 12.6663 +
 12.6664 +Feather                     Standards Track                   [Page 119]
 12.6665 +
 12.6666 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6667 +
 12.6668 +
 12.6669 +   Response code 430
 12.6670 +      Generated by: ARTICLE, BODY, HDR, HEAD, OVER, STAT
 12.6671 +      Meaning: no article with that message-id.
 12.6672 +
 12.6673 +   Response code 435
 12.6674 +      Generated by: IHAVE (first stage)
 12.6675 +      Meaning: article not wanted.
 12.6676 +
 12.6677 +   Response code 436
 12.6678 +      Generated by: IHAVE (either stage)
 12.6679 +      Meaning: transfer not possible (first stage) or failed (second
 12.6680 +      stage); try again later.
 12.6681 +
 12.6682 +   Response code 437
 12.6683 +      Generated by: IHAVE (second stage)
 12.6684 +      Meaning: transfer rejected; do not retry.
 12.6685 +
 12.6686 +   Response code 440
 12.6687 +      Generated by: POST (first stage)
 12.6688 +      Meaning: posting not permitted.
 12.6689 +
 12.6690 +   Response code 441
 12.6691 +      Generated by: POST (second stage)
 12.6692 +      Meaning: posting failed.
 12.6693 +
 12.6694 +   Response code 480
 12.6695 +      Generic response
 12.6696 +      Meaning: command unavailable until the client has authenticated
 12.6697 +      itself.
 12.6698 +
 12.6699 +   Response code 483
 12.6700 +      Generic response
 12.6701 +      Meaning: command unavailable until suitable privacy has been
 12.6702 +      arranged.
 12.6703 +
 12.6704 +   Response code 500
 12.6705 +      Generic response
 12.6706 +      Meaning: unknown command.
 12.6707 +
 12.6708 +   Response code 501
 12.6709 +      Generic response
 12.6710 +      Meaning: syntax error in command.
 12.6711 +
 12.6712 +
 12.6713 +
 12.6714 +
 12.6715 +
 12.6716 +
 12.6717 +
 12.6718 +
 12.6719 +
 12.6720 +Feather                     Standards Track                   [Page 120]
 12.6721 +
 12.6722 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6723 +
 12.6724 +
 12.6725 +   Response code 502
 12.6726 +      Generic response and generated by initial connection
 12.6727 +
 12.6728 +      Meaning for the initial connection and the MODE READER command:
 12.6729 +      service permanently unavailable (the server immediately closes the
 12.6730 +      connection).
 12.6731 +
 12.6732 +      Meaning for all other commands: command not permitted (and there
 12.6733 +      is no way for the client to change this).
 12.6734 +
 12.6735 +   Response code 503
 12.6736 +      Generic response
 12.6737 +      Meaning: feature not supported.
 12.6738 +
 12.6739 +   Response code 504
 12.6740 +      Generic response
 12.6741 +      Meaning: error in base64-encoding [RFC4648] of an argument.
 12.6742 +
 12.6743 +Appendix D.  Changes from RFC 977
 12.6744 +
 12.6745 +   In general every attempt has been made to ensure that the protocol
 12.6746 +   specification in this document is compatible with the version
 12.6747 +   specified in RFC 977 [RFC977] and the various facilities adopted from
 12.6748 +   RFC 2980 [RFC2980].  However, there have been a number of changes,
 12.6749 +   some compatible and some not.
 12.6750 +
 12.6751 +   This appendix lists these changes.  It is not guaranteed to be
 12.6752 +   exhaustive or correct and MUST NOT be relied on.
 12.6753 +
 12.6754 +   o  A formal syntax specification (Section 9) has been added.
 12.6755 +
 12.6756 +   o  The default character set is changed from US-ASCII [ANSI1986] to
 12.6757 +      UTF-8 [RFC3629] (note that US-ASCII is a subset of UTF-8).  This
 12.6758 +      matter is discussed further in Section 10.
 12.6759 +
 12.6760 +   o  All articles are required to have a message-id, eliminating the
 12.6761 +      "<0>" placeholder used in RFC 977 in some responses.
 12.6762 +
 12.6763 +   o  The newsgroup name matching capabilities already documented in
 12.6764 +      RFC 977 ("wildmats", Section 4) are clarified and extended.  The
 12.6765 +      new facilities (e.g., the use of commas and exclamation marks) are
 12.6766 +      allowed wherever wildmats appear in the protocol.
 12.6767 +
 12.6768 +   o  Support for pipelining of commands (Section 3.5) is made
 12.6769 +      mandatory.
 12.6770 +
 12.6771 +
 12.6772 +
 12.6773 +
 12.6774 +
 12.6775 +
 12.6776 +Feather                     Standards Track                   [Page 121]
 12.6777 +
 12.6778 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6779 +
 12.6780 +
 12.6781 +   o  The principles behind response codes (Section 3.2) have been
 12.6782 +      tidied up.  In particular:
 12.6783 +
 12.6784 +      *  the x8x response code family, formerly used for private
 12.6785 +         extensions, is now reserved for authentication and privacy
 12.6786 +         extensions;
 12.6787 +
 12.6788 +      *  the x9x response code family, formerly intended for debugging
 12.6789 +         facilities, are now reserved for private extensions;
 12.6790 +
 12.6791 +      *  the 502 and 503 generic response codes (Section 3.2.1) have
 12.6792 +         been redefined;
 12.6793 +
 12.6794 +      *  new 401, 403, 480, 483, and 504 generic response codes have
 12.6795 +         been added.
 12.6796 +
 12.6797 +   o  The rules for article numbering (Section 6) have been clarified
 12.6798 +      (also see Section 6.1.1.2).
 12.6799 +
 12.6800 +   o  The SLAVE command (which was ill-defined) is removed from the
 12.6801 +      protocol.
 12.6802 +
 12.6803 +   o  Four-digit years are permitted in the NEWNEWS (Section 7.4) and
 12.6804 +      NEWGROUPS (Section 7.3) commands (two-digit years are still
 12.6805 +      permitted).  The optional distribution parameter to these commands
 12.6806 +      has been removed.
 12.6807 +
 12.6808 +   o  The LIST command (Section 7.6.1) is greatly extended; the original
 12.6809 +      is available as LIST ACTIVE, while new variants include
 12.6810 +      ACTIVE.TIMES, DISTRIB.PATS, and NEWSGROUPS.  A new "m" status flag
 12.6811 +      is added to the LIST ACTIVE response.
 12.6812 +
 12.6813 +   o  A new CAPABILITIES command (Section 5.2) allows clients to
 12.6814 +      determine what facilities are supported by a server.
 12.6815 +
 12.6816 +   o  The DATE command (Section 7.1) is adopted from RFC 2980
 12.6817 +      effectively unchanged.
 12.6818 +
 12.6819 +   o  The LISTGROUP command (Section 6.1.2) is adopted from RFC 2980.
 12.6820 +      An optional range argument has been added, and the 211 initial
 12.6821 +      response line now has the same format as the 211 response from the
 12.6822 +      GROUP command.
 12.6823 +
 12.6824 +   o  The MODE READER command (Section 5.3) is adopted from RFC 2980 and
 12.6825 +      its meaning and effects clarified.
 12.6826 +
 12.6827 +   o  The XHDR command in RFC 2980 has been formalised as the new HDR
 12.6828 +      (Section 8.5) and LIST HEADERS (Section 8.6) commands.
 12.6829 +
 12.6830 +
 12.6831 +
 12.6832 +Feather                     Standards Track                   [Page 122]
 12.6833 +
 12.6834 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6835 +
 12.6836 +
 12.6837 +   o  The XOVER command in RFC 2980 has been formalised as the new OVER
 12.6838 +      (Section 8.3) and LIST OVERVIEW.FMT (Section 8.4) commands.  The
 12.6839 +      former can be applied to a message-id as well as to a range.
 12.6840 +
 12.6841 +   o  The concept of article metadata (Section 8.1) has been formalised,
 12.6842 +      allowing the Bytes and Lines pseudo-headers to be deprecated.
 12.6843 +
 12.6844 +   Client authors should note in particular that lack of support for the
 12.6845 +   CAPABILITIES command is a good indication that the server does not
 12.6846 +   support this specification.
 12.6847 +
 12.6848 +
 12.6849 +
 12.6850 +
 12.6851 +
 12.6852 +
 12.6853 +
 12.6854 +
 12.6855 +
 12.6856 +
 12.6857 +
 12.6858 +
 12.6859 +
 12.6860 +
 12.6861 +
 12.6862 +
 12.6863 +
 12.6864 +
 12.6865 +
 12.6866 +
 12.6867 +
 12.6868 +
 12.6869 +
 12.6870 +
 12.6871 +
 12.6872 +
 12.6873 +
 12.6874 +
 12.6875 +
 12.6876 +
 12.6877 +
 12.6878 +
 12.6879 +
 12.6880 +
 12.6881 +
 12.6882 +
 12.6883 +
 12.6884 +
 12.6885 +
 12.6886 +
 12.6887 +
 12.6888 +Feather                     Standards Track                   [Page 123]
 12.6889 +
 12.6890 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6891 +
 12.6892 +
 12.6893 +Author's Address
 12.6894 +
 12.6895 +   Clive D.W. Feather
 12.6896 +   THUS plc
 12.6897 +   322 Regents Park Road
 12.6898 +   London
 12.6899 +   N3  2QQ
 12.6900 +   United Kingdom
 12.6901 +
 12.6902 +   Phone: +44 20 8495 6138
 12.6903 +   Fax:   +44 870 051 9937
 12.6904 +   EMail: clive@demon.net
 12.6905 +   URI:   http://www.davros.org/
 12.6906 +
 12.6907 +
 12.6908 +
 12.6909 +
 12.6910 +
 12.6911 +
 12.6912 +
 12.6913 +
 12.6914 +
 12.6915 +
 12.6916 +
 12.6917 +
 12.6918 +
 12.6919 +
 12.6920 +
 12.6921 +
 12.6922 +
 12.6923 +
 12.6924 +
 12.6925 +
 12.6926 +
 12.6927 +
 12.6928 +
 12.6929 +
 12.6930 +
 12.6931 +
 12.6932 +
 12.6933 +
 12.6934 +
 12.6935 +
 12.6936 +
 12.6937 +
 12.6938 +
 12.6939 +
 12.6940 +
 12.6941 +
 12.6942 +
 12.6943 +
 12.6944 +Feather                     Standards Track                   [Page 124]
 12.6945 +
 12.6946 +RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 12.6947 +
 12.6948 +
 12.6949 +Full Copyright Statement
 12.6950 +
 12.6951 +Copyright (C) The Internet Society (2006).
 12.6952 +
 12.6953 +   This document is subject to the rights, licenses and restrictions
 12.6954 +   contained in BCP 78, and except as set forth therein, the authors
 12.6955 +   retain all their rights.
 12.6956 +
 12.6957 +   This document and the information contained herein are provided on an
 12.6958 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 12.6959 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
 12.6960 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
 12.6961 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
 12.6962 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 12.6963 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 12.6964 +
 12.6965 +Intellectual Property
 12.6966 +
 12.6967 +   The IETF takes no position regarding the validity or scope of any
 12.6968 +   Intellectual Property Rights or other rights that might be claimed to
 12.6969 +   pertain to the implementation or use of the technology described in
 12.6970 +   this document or the extent to which any license under such rights
 12.6971 +   might or might not be available; nor does it represent that it has
 12.6972 +   made any independent effort to identify any such rights.  Information
 12.6973 +   on the procedures with respect to rights in RFC documents can be
 12.6974 +   found in BCP 78 and BCP 79.
 12.6975 +
 12.6976 +   Copies of IPR disclosures made to the IETF Secretariat and any
 12.6977 +   assurances of licenses to be made available, or the result of an
 12.6978 +   attempt made to obtain a general license or permission for the use of
 12.6979 +   such proprietary rights by implementers or users of this
 12.6980 +   specification can be obtained from the IETF on-line IPR repository at
 12.6981 +   http://www.ietf.org/ipr.
 12.6982 +
 12.6983 +   The IETF invites any interested party to bring to its attention any
 12.6984 +   copyrights, patents or patent applications, or other proprietary
 12.6985 +   rights that may cover technology that may be required to implement
 12.6986 +   this standard.  Please address the information to the IETF at ietf-
 12.6987 +   ipr@ietf.org.
 12.6988 +
 12.6989 +Acknowledgement
 12.6990 +
 12.6991 +   Funding for the RFC Editor function is provided by the IETF
 12.6992 +   Administrative Support Activity (IASA).
 12.6993 +
 12.6994 +
 12.6995 +
 12.6996 +
 12.6997 +
 12.6998 +
 12.6999 +
 12.7000 +Feather                     Standards Track                   [Page 125]
 12.7001 +
    13.1 Binary file RFC3977.pdf has changed
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/SConstruct	Fri Jun 26 16:48:50 2009 +0200
    14.3 @@ -0,0 +1,16 @@
    14.4 +# This file is used to build and automatically test sonews
    14.5 +
    14.6 +import os
    14.7 +env = Environment()
    14.8 +
    14.9 +env['ENV']['LANG'] = 'en_GB.UTF-8'
   14.10 +env['JAVACFLAGS']    = '-source 1.6 -target 1.6'
   14.11 +env['JAVACLASSPATH'] = '/usr/share/java/junit4.jar:/usr/share/java/glassfish-mail.jar:/usr/share/java/servlet-api-2.5.jar:/usr/share/java/jchart2d.jar:classes'
   14.12 +
   14.13 +# Build Java classes
   14.14 +classes = env.Java(target='classes', source=['org/sonews/'])
   14.15 +test_classes   = env.Java(target='classes', source=['test'])
   14.16 +
   14.17 +# Setting dependencies
   14.18 +Depends(test_classes, classes)
   14.19 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/bin/sonews-web.sh	Fri Jun 26 16:48:50 2009 +0200
    15.3 @@ -0,0 +1,10 @@
    15.4 +#!/bin/bash
    15.5 +SCRIPTROOT=$(dirname $0)
    15.6 +CLASSPATH=$SCRIPTROOT/lib/jchart2d.jar:\
    15.7 +$SCRIPTROOT/lib/sonews.jar:\
    15.8 +$SCRIPTROOT/lib/servlet-api-2.5.jar
    15.9 +ARG0=org.sonews.web.SonewsServlet@sonews
   15.10 +ARG1=org.sonews.web.SonewsConfigServlet@sonews/config
   15.11 +ARG2=org.sonews.web.SonewsPeerServlet@sonews/peer
   15.12 +ARG3=org.sonews.web.SonewsChartServlet@sonews/chart
   15.13 +java -cp $CLASSPATH org.sonews.kitten.Main -s $ARG0 -s $ARG1 -s $ARG2 -s $ARG3
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/bin/sonews.sh	Fri Jun 26 16:48:50 2009 +0200
    16.3 @@ -0,0 +1,35 @@
    16.4 +#!/bin/bash
    16.5 +SCRIPTROOT=$(pwd)
    16.6 +CLASSPATH=$SCRIPTROOT/lib/sonews.jar:\
    16.7 +$SCRIPTROOT/lib/mysql-connector-java.jar:\
    16.8 +$SCRIPTROOT/lib/glassfish-mail.jar:\
    16.9 +$SCRIPTROOT/lib/postgresql.jar
   16.10 +
   16.11 +LOGFILE=sonews.log
   16.12 +PIDFILE=sonews.pid
   16.13 +ARGS=$@
   16.14 +
   16.15 +MAINCLASS=org.sonews.daemon.Main
   16.16 +JAVA=java
   16.17 +
   16.18 +case "$1" in
   16.19 +  start)
   16.20 +    echo "Starting sonews Newsserver..."
   16.21 +    $JAVA -classpath $CLASSPATH $MAINCLASS $ARGS &> $LOGFILE &
   16.22 +    echo $! > $PIDFILE
   16.23 +    ;;
   16.24 +  stop)
   16.25 +    echo "Stopping sonews Newsserver..."
   16.26 +    PID=`cat $PIDFILE`
   16.27 +    kill -15 $PID
   16.28 +    ;;
   16.29 +  setup)
   16.30 +    $JAVA -classpath $CLASSPATH org.sonews.util.DatabaseSetup
   16.31 +    ;;
   16.32 +  purge)
   16.33 +    $JAVA -classpath $CLASSPATH org.sonews.util.Purger
   16.34 +    ;;
   16.35 +
   16.36 +  *)
   16.37 +    echo "Usage: sonews [start|stop|setup|purge]"
   16.38 +esac
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/doc/config.xsl	Fri Jun 26 16:48:50 2009 +0200
    17.3 @@ -0,0 +1,17 @@
    17.4 +<?xml version="1.0"?>
    17.5 +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    17.6 +                xmlns:fo="http://www.w3.org/1999/XSL/Format"
    17.7 +                version="1.0">
    17.8 +  <xsl:param name="use.id.as.filename" select="1"/>
    17.9 +  <xsl:param name="admon.graphics" select="1"/>
   17.10 +  <xsl:param name="admon.graphics.path"></xsl:param>
   17.11 +  <xsl:param name="chunk.section.depth" select="0"></xsl:param>
   17.12 +  <xsl:param name="html.stylesheet" select="'sonews.css'"/>
   17.13 +<xsl:template name="user.footer.navigation">
   17.14 +  <p class="copyright">
   17.15 +  <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/80x15.png" /></a> This work by <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Christian Lins</span> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share Alike 3.0 License</a>.
   17.16 +  </p>
   17.17 +</xsl:template>
   17.18 +
   17.19 +</xsl:stylesheet>
   17.20 +
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/doc/makedoc	Fri Jun 26 16:48:50 2009 +0200
    18.3 @@ -0,0 +1,1 @@
    18.4 +xmlto --skip-validation html -m config.xsl sonews.xml
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/doc/sonews.css	Fri Jun 26 16:48:50 2009 +0200
    19.3 @@ -0,0 +1,35 @@
    19.4 +body 
    19.5 +{
    19.6 +    font-family: Liberation Sans,Verdana,sans-serif;
    19.7 +    font-size: 11pt;
    19.8 +}
    19.9 +
   19.10 +.screen {
   19.11 +        font-family: monospace;
   19.12 +        font-size: 1em;
   19.13 +        display: block;
   19.14 +        padding: 10px;
   19.15 +        border: 1px solid #bbb;
   19.16 +        background-color: #eee;
   19.17 +        color: #000;   
   19.18 +        overflow: auto;
   19.19 +        border-radius: 2.5px;
   19.20 +        -moz-border-radius: 2.5px;
   19.21 +        margin: 0.5em 2em;
   19.22 + 
   19.23 +}
   19.24 +
   19.25 +.programlisting {
   19.26 +        font-family: monospace;
   19.27 +        font-size: 1em;
   19.28 +        display: block;
   19.29 +        padding: 10px;
   19.30 +        border: 1px solid #bbb;
   19.31 +        background-color: #ddd;
   19.32 +        color: #000;   
   19.33 +        overflow: auto;
   19.34 +        border-radius: 2.5px;
   19.35 +        -moz-border-radius: 2.5px;
   19.36 +        margin: 0.5em 2em;
   19.37 +}
   19.38 +
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/doc/sonews.xml	Fri Jun 26 16:48:50 2009 +0200
    20.3 @@ -0,0 +1,254 @@
    20.4 +<?xml version="1.0"?>
    20.5 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
    20.6 +  <!ENTITY tex "TeX">
    20.7 +  <!ENTITY latex "LaTeX">
    20.8 +]>
    20.9 +<book id="sonews.xml" lang="en">
   20.10 +  <title>sonews Usenet News Server</title>
   20.11 +  <para>
   20.12 +    <emphasis role="bold">sonews</emphasis> is NNTP server than can provide 
   20.13 +    access to both local and global Usenets newsgroups. It is written in 
   20.14 +    <ulink url="http://java.sun.com/">Java</ulink> and uses a relational
   20.15 +    database as backend.
   20.16 +  </para>
   20.17 +  <para>
   20.18 +    <emphasis role="bold">2009/06/29</emphasis>: 
   20.19 +    <emphasis>sonews/0.5.0</emphasis> 
   20.20 +    (<ulink url="files/sonews-0.5.0.tar.bz2">binary tarball</ulink>,
   20.21 +    <ulink url="files/sonews-0.5.0-src.tar.bz2">source tarball</ulink>) final 
   20.22 +    released. 
   20.23 +    The setup is a little clumsy but the software is stable and works well.
   20.24 +  </para>
   20.25 +  
   20.26 +  <chapter>
   20.27 +    <title>Introduction</title>
   20.28 +    <para>sonews is a RCF3977 compliant NNTP Usenet server. 
   20.29 +    It is written in Java and uses a relation database management system
   20.30 +    (RDBMS) as backend (currently
   20.31 +    <ulink url="http://www.postgresql.com/">PostgreSQL</ulink> and
   20.32 +    <ulink url="http://www.mysql.com/">MySQL</ulink>).
   20.33 +    sonews is highly multithreaded and uses Java NIO asynchronous sockets
   20.34 +    to handle thousands of concurrent connections.</para>
   20.35 +    <para>sonews is Free and Open Source Software (FOSS) licensed under the 
   20.36 +    terms of the
   20.37 +    <ulink url="http://www.gnu.org/licenses/gpl.html">GNU General Public License</ulink>
   20.38 +    Version 3 (or later).</para>
   20.39 +
   20.40 +    <sect1 label="1.1">
   20.41 +      <title>History</title>
   20.42 +      <para>Ancestor of sonews is probably the Neat NNTP Daemon (n3tpd) 
   20.43 +      although there is very little code in sonews that can be identified
   20.44 +      as direct derivation.
   20.45 +      sonews was developed as diploma thesis project of Christian Lins at
   20.46 +      <ulink url="http://de.sun.com/">StarOffice development</ulink>
   20.47 +      in Hamburg and is now a Free Software project.</para>
   20.48 +    </sect1>
   20.49 +
   20.50 +    <sect1 label="1.2">
   20.51 +      <title>Roadmap</title>
   20.52 +      <sect2 label="1.2.1">
   20.53 +        <title>sonews/0.6</title>
   20.54 +        <para>Planned to implement the XPAT command for searching, correctly 
   20.55 +        hashed Message-Ids and a news purging command.
   20.56 +        See <ulink url="http://bugs.xerxys.info/">Bugtracker</ulink> for
   20.57 +        issues with target sonews/0.6.x.</para>
   20.58 +      </sect2>
   20.59 +    </sect1>
   20.60 +  </chapter>
   20.61 +
   20.62 +  <chapter label="2">
   20.63 +    <title>Installation and initial setup</title>
   20.64 +    <sect1 label="2.1">
   20.65 +      <title>Download &amp; Installation</title>
   20.66 +      <sect2 label="2.1.1">
   20.67 +        <title>Debian based systems</title>
   20.68 +        <para>You can install sonews with 
   20.69 +        <ulink url="http://www.debian.org/doc/manuals/apt-howto/">APT</ulink>
   20.70 +        easily.
   20.71 +        Add the following line to /etc/apt/sources.list:</para>
   20.72 +        <screen>deb http://packages.xerxys.info/debian/ unstable main
   20.73 +        </screen>
   20.74 +        <para>And add the GPG-Key for package authentification, see 
   20.75 +        <ulink url="http://packages.xerxys.info/debian/">Xerxys Debian Repository</ulink>
   20.76 +        for more details.</para>
   20.77 +        <para>Then force an update of your local package list:</para>
   20.78 +        <screen># apt-get update
   20.79 +</screen>
   20.80 +        <para>To install sonews and all prerequisites issue the following command:</para>
   20.81 +        <screen># apt-get install sonews
   20.82 +        </screen>
   20.83 +        <para>This method should work for all recent Debian-based distributions
   20.84 +(<ulink url="http://www.debian.org/">Debian</ulink>, <ulink url="http://www.ubuntu.com/">Ubuntu</ulink>, etc.).</para>
   20.85 +      </sect2>
   20.86 +
   20.87 +      <sect2 label="2.1.2">
   20.88 +        <title>Other *nix systems</title>
   20.89 +        <para>See <ulink url="files/">Files Section</ulink> for recent binary and source tarballs.</para>
   20.90 +        <para>Use the binary archive and extract it in a directory of your choice. Make sure your system
   20.91 +provides the necessary prerequisites:</para>
   20.92 +        <itemizedlist>
   20.93 +          <listitem>
   20.94 +            <para>Java6 compatible runtime (JRE)</para>
   20.95 +          </listitem>
   20.96 +          <listitem>
   20.97 +            <para>Java Mail API implementation, e.g. <ulink url="http://java.sun.com/products/javamail/">Sun Java Mail</ulink>.
   20.98 +GNU JavaMail has a broken POP3 Provider and does not work with sonews.</para>
   20.99 +          </listitem>
  20.100 +          <listitem>
  20.101 +            <para>JSP Servlet Container (e.g. 
  20.102 +            <ulink url="http://kitten.sonews.org/">Kitten</ulink>) [optional]</para>
  20.103 +          </listitem>
  20.104 +        </itemizedlist>
  20.105 +      </sect2>
  20.106 +    </sect1>
  20.107 +
  20.108 +    <sect1 label="2.2">
  20.109 +      <title>Initial database setup</title>
  20.110 +      <para>Before you start sonews, you must prepare the database. Currently sonews is known
  20.111 +to work with PostgreSQL and MySQL.</para>
  20.112 +      <para>It is highly recommended to create an own database for every sonews instance, e.g.
  20.113 +called 'sonews'. Additionally, it is recommended to create a unique database user
  20.114 +for sonews, e.g. 'sonewsuser'. Please do not use the root user for sonews!
  20.115 +The sonews user needs rights for SELECT, INSERT and UPDATE statements.
  20.116 +Refer to the database's manual for instructions.</para>
  20.117 +      <para>You will find the SQL Schema definitions in the helpers subdirectory of
  20.118 +the source and binary distributions. You can create the tables manually using
  20.119 +this templates or you can use the setup helper:</para>
  20.120 +      <screen>user@debian$ sonews setup
  20.121 +</screen>
  20.122 +      <para>or on other *nix systems:</para>
  20.123 +      <screen>user@nix$ java -jar sonews.jar org.sonews.util.DatabaseSetup
  20.124 +</screen>
  20.125 +      <para>The tool will ask for some information about your database environment,
  20.126 +connect to the database, create the tables and creates a default bootstrap
  20.127 +config file called sonews.conf.</para>
  20.128 +    </sect1>
  20.129 +  </chapter>
  20.130 +
  20.131 +  <chapter label="3">
  20.132 +    <title>Running sonews</title>
  20.133 +    <sect1 label="3.1">
  20.134 +      <title>Configuration</title>
  20.135 +      <para>There is a bootstrap configuration in /etc/sonews/sonews.conf and a regular configuration
  20.136 +in the database table config.</para>
  20.137 +      <para>There are various configuration values that can be adapted:</para>
  20.138 +      <variablelist>
  20.139 +        <varlistentry>
  20.140 +          <term>&lsquo;<literal>sonews.article.maxsize</literal>&rsquo;</term>
  20.141 +          <listitem>
  20.142 +            <para>Maximum allowed body size of a news message given in kilobytes. Please note that
  20.143 +for MySQL the &lsquo;<literal>max_allowed_packet</literal>&rsquo; configuration variable must
  20.144 +be set to a value higher than &lsquo;<literal>sonews.article.maxsize</literal>&rsquo; otherwise posting
  20.145 +of large mails will fail.</para>
  20.146 +          </listitem>
  20.147 +        </varlistentry>
  20.148 +          <varlistentry>
  20.149 +          <term>&lsquo;<literal>sonews.debug</literal>&rsquo;</term>
  20.150 +          <listitem>
  20.151 +            <para>
  20.152 +            If set to true every(!) data going through sonews' socket
  20.153 +            is written to sonews.log. After a night the logfile can be
  20.154 +            several gigabytes large, so be careful with this setting.
  20.155 +            </para>
  20.156 +          </listitem>
  20.157 +        </varlistentry>
  20.158 +        <varlistentry>
  20.159 +          <term>&lsquo;<literal>sonews.hostname</literal>&rsquo;</term>
  20.160 +          <listitem>
  20.161 +            <para>Canonical name of the server instance. This variable is part of the server's
  20.162 +hello message to the client and used to generate Message-Ids.</para>
  20.163 +          </listitem>
  20.164 +        </varlistentry>
  20.165 +        <varlistentry>
  20.166 +          <term>&lsquo;<literal>sonews.timeout</literal>&rsquo;</term>
  20.167 +          <listitem>
  20.168 +            <para>Socket timeout for client connections in seconds.</para>
  20.169 +          </listitem>
  20.170 +        </varlistentry>
  20.171 +        <varlistentry>
  20.172 +          <term>&lsquo;<literal>sonews.port</literal>&rsquo;</term>
  20.173 +          <listitem>
  20.174 +            <para>Listening port of sonews daemon.</para>
  20.175 +          </listitem>
  20.176 +        </varlistentry>
  20.177 +      </variablelist>
  20.178 +    </sect1>
  20.179 +
  20.180 +    <sect1 label="3.2">
  20.181 +      <title>Command line arguments</title>
  20.182 +      <para>If you like to start sonews directly, you can use one of the following
  20.183 +arguments:</para>
  20.184 +      <screen>java -jar sonews.jar [arguments]
  20.185 +        where arguments:
  20.186 +    -c|-config         &lt;path to config file&gt; if custom config file preferred
  20.187 +    -dumpjdbcdriver    Prints out a list of available JDBC drivers
  20.188 +    -feed              Enables feed daemon for pulling news from peer servers
  20.189 +    -h|-help           This output
  20.190 +    -mlgw              Enables the Mailinglist Gateway poller
  20.191 +    -p portnumber      Port on which sonews is listening for incoming connections.
  20.192 +                       Overrides port settings in config file and database.
  20.193 +
  20.194 +</screen>
  20.195 +    </sect1>
  20.196 +
  20.197 +    <sect1 label="3.3">
  20.198 +      <title>Webinterface</title>
  20.199 +      <para>The package sonews-web provides an optional webinterface that can be used to
  20.200 +review statistical information and configuration values of sonews.</para>
  20.201 +      <screen>sonews-web start|stop
  20.202 +</screen>
  20.203 +      <para>The webinterface uses the the lightweight Servlet Container Kitten and is
  20.204 +per default listening on HTTP-Port 8080 (go to http://localhost:8080/sonews).</para>
  20.205 +    </sect1>
  20.206 +  </chapter>
  20.207 +
  20.208 +  <chapter label="4">
  20.209 +    <title>Development</title>
  20.210 +    <para>You're welcome to create patches with bugfixes or additional features. The
  20.211 +Mercurial DSCM makes this step an easy task.</para>
  20.212 +    <para>Just clone the public <ulink url="http://www.selenic.com/mercurial/">Mercurial</ulink> repository:</para>
  20.213 +    <screen>hg clone http://code.xerxys.info:8000/hg/sonews/trunk sonews-trunk
  20.214 +</screen>
  20.215 +    <para>Then make your changes, create a bundle of changesets and send this to me via email.
  20.216 +Or ask for push access to the public repository.</para>
  20.217 +    <para>
  20.218 +        There is a nightly generated <ulink url="apidoc/">Javadoc API documentation</ulink> that will help
  20.219 +        you to get in touch with the sonews source.
  20.220 +    </para>
  20.221 +    <para>Some debugging hints: if the server blocks and does not longer respond you
  20.222 +probably found a deadlock. Do not kill the process with "kill -9 &lt;pid&gt;"
  20.223 +but send a SIGQUIT signal with "kill -3 &lt;pid&gt;" and the Java VM will output
  20.224 +a stracktrace of all threads. This output is the most valuable information to
  20.225 +fix the deadlock.</para>
  20.226 +
  20.227 +    <sect1 label="4.1">
  20.228 +      <title>Contributors</title>
  20.229 +      <para>Maintainer and project lead:
  20.230 +Christian Lins (contact christian.lins (at) fh-osnabrueck.de)</para>
  20.231 +    </sect1>
  20.232 +
  20.233 +    <sect1 label="4.2">
  20.234 +      <title>Sponsors</title>
  20.235 +      <para>The author thanks <ulink url="http://www.sun.com/">Sun Microsystems</ulink> for fully
  20.236 +financing the first version of sonews. A really free software supporting company!</para>
  20.237 +      <para>If you like to support sonews with a donation of any kind (hardware, books, money, donuts,...),
  20.238 + feel free to contact the project leader.
  20.239 +A friendly email or a bug report is most welcome, too :-)</para>
  20.240 +    </sect1>
  20.241 +  </chapter>
  20.242 +
  20.243 +  <chapter label="5">
  20.244 +    <title>Links and further information</title>
  20.245 +    <itemizedlist>
  20.246 +      <listitem>
  20.247 +        <para><ulink url="http://bugs.xerxys.info/">Bugtracker</ulink>, register necessary, see project 'sonews'.</para>
  20.248 +      </listitem>
  20.249 +      <listitem>
  20.250 +        <para><ulink url="http://www.sun.com/">Sun Microsystems</ulink>, friendly sponsor.</para>
  20.251 +      </listitem>
  20.252 +      <listitem>
  20.253 +        <para><ulink url="http://www.fh-osnabrueck">University of Applied Sciences Osnabrueck</ulink></para>
  20.254 +      </listitem>
  20.255 +    </itemizedlist>
  20.256 +  </chapter>
  20.257 +</book>
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/helpers/copyright	Fri Jun 26 16:48:50 2009 +0200
    21.3 @@ -0,0 +1,23 @@
    21.4 +Upstream Author:
    21.5 +
    21.6 +    Christian Lins <christian.lins@web.de>
    21.7 +
    21.8 +Copyright:
    21.9 +
   21.10 +    Copyright (C) 2009 Christian Lins
   21.11 +
   21.12 +License:
   21.13 +
   21.14 +  This program is free software: you can redistribute it and/or modify
   21.15 +  it under the terms of the GNU General Public License as published by
   21.16 +  the Free Software Foundation, either version 3 of the License, or
   21.17 +  (at your option) any later version.
   21.18 +  
   21.19 +  This program is distributed in the hope that it will be useful,
   21.20 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
   21.21 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   21.22 +  GNU General Public License for more details.
   21.23 +  
   21.24 +  You should have received a copy of the GNU General Public License
   21.25 +  along with this program.  If not, see <http://www.gnu.org/licenses/>.
   21.26 +
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/helpers/database_mysql5_tmpl.sql	Fri Jun 26 16:48:50 2009 +0200
    22.3 @@ -0,0 +1,158 @@
    22.4 +/* 
    22.5 +  Create a database at first:
    22.6 +    CREATE DATABASE sonews CHARACTER SET utf8
    22.7 +*/
    22.8 +
    22.9 +/* 
   22.10 +  flags:
   22.11 +  If bit 0 is set, groups is a mirrorred mailing list. 
   22.12 +  If not set default newsgroup.
   22.13 +
   22.14 +  Normalization: 1NF, 2NF, 3NF
   22.15 +*/
   22.16 +CREATE TABLE groups 
   22.17 +(
   22.18 +  group_id      SERIAL,
   22.19 +  name          VARCHAR(80) NOT NULL,
   22.20 +  flags         TINYINT UNSIGNED DEFAULT 0,
   22.21 +
   22.22 +  PRIMARY KEY(group_id),
   22.23 +  UNIQUE(name)
   22.24 +)
   22.25 +ENGINE = INNODB
   22.26 +CHARACTER SET utf8;
   22.27 +
   22.28 +CREATE TABLE articles 
   22.29 +(
   22.30 +  article_id    INT,
   22.31 +  body          LONGBLOB,
   22.32 +
   22.33 +  PRIMARY KEY(article_id)
   22.34 +)
   22.35 +ENGINE = INNODB
   22.36 +CHARACTER SET utf8;
   22.37 +
   22.38 +CREATE TABLE article_ids
   22.39 +(
   22.40 +  article_id  INT REFERENCES articles.article_id ON DELETE CASCADE,
   22.41 +  message_id  VARCHAR(255),
   22.42 +
   22.43 +  PRIMARY KEY(article_id),
   22.44 +  UNIQUE(message_id)
   22.45 +)
   22.46 +ENGINE = INNODB
   22.47 +CHARACTER SET utf8;
   22.48 +
   22.49 +CREATE TABLE headers
   22.50 +(
   22.51 +  article_id    INT REFERENCES articles.article_id ON DELETE CASCADE,
   22.52 +  header_key    VARCHAR(255),
   22.53 +  header_value  TEXT, /* Max. 64k */
   22.54 +  header_index  INT,
   22.55 +
   22.56 +  PRIMARY KEY(article_id, header_key, header_index)
   22.57 +)
   22.58 +ENGINE = INNODB
   22.59 +CHARACTER SET utf8;
   22.60 +
   22.61 +/*
   22.62 +  Normalization: 1NF, 2NF
   22.63 +*/
   22.64 +CREATE TABLE postings 
   22.65 +(
   22.66 +  group_id      INTEGER,
   22.67 +  article_id    INTEGER REFERENCES articles.article_id ON DELETE CASCADE,
   22.68 +  article_index INTEGER NOT NULL, 
   22.69 +
   22.70 +  PRIMARY KEY(group_id, article_id)
   22.71 +)
   22.72 +ENGINE = INNODB
   22.73 +CHARACTER SET utf8;
   22.74 +
   22.75 +/* 
   22.76 +  Table for association of newsgroups and mailing-lists 
   22.77 +
   22.78 +  Normalization: 1NF, 2NF, 3NF
   22.79 +*/
   22.80 +CREATE TABLE groups2list
   22.81 +(
   22.82 +  group_id    INTEGER REFERENCES groups.group_id ON DELETE CASCADE,
   22.83 +  listaddress VARCHAR(255),
   22.84 +
   22.85 +  PRIMARY KEY(group_id, listaddress),
   22.86 +  UNIQUE(listaddress)
   22.87 +)
   22.88 +ENGINE = INNODB
   22.89 +CHARACTER SET utf8;
   22.90 +
   22.91 +/* 
   22.92 +  Configuration table, containing key/value pairs 
   22.93 +
   22.94 +  Normalization: 1NF, 2NF, 3NF
   22.95 +*/
   22.96 +CREATE TABLE config
   22.97 +(
   22.98 +  config_key     VARCHAR(255),
   22.99 +  config_value   TEXT,
  22.100 +
  22.101 +  PRIMARY KEY(config_key)
  22.102 +)
  22.103 +ENGINE = INNODB
  22.104 +CHARACTER SET utf8;
  22.105 +
  22.106 +/* 
  22.107 +  Newsserver peers 
  22.108 +  feedtype: 0: pullfeed 1: pushfeed
  22.109 +  Normalization: 1NF (atomic values), 2NF
  22.110 +*/
  22.111 +CREATE TABLE peers
  22.112 +(
  22.113 +  peer_id     SERIAL,
  22.114 +  host        VARCHAR(255),
  22.115 +  port        SMALLINT UNSIGNED,
  22.116 +
  22.117 +  PRIMARY KEY(peer_id),
  22.118 +  UNIQUE(host, port)
  22.119 +)
  22.120 +ENGINE = INNODB
  22.121 +CHARACTER SET utf8;
  22.122 +
  22.123 +/* 
  22.124 +  List of newsgroups to feed into sonews 
  22.125 +
  22.126 +  Normalization: 1NF, 2NF, 3NF
  22.127 +*/
  22.128 +CREATE TABLE peer_subscriptions
  22.129 +(
  22.130 +  peer_id    INTEGER REFERENCES peers.peer_id ON DELETE CASCADE,
  22.131 +  group_id   INTEGER REFERENCES groups.group_id ON DELETE CASCADE,
  22.132 +  feedtype   TINYINT UNSIGNED DEFAULT 0,
  22.133 +
  22.134 +  PRIMARY KEY(peer_id, group_id, feedtype)
  22.135 +)
  22.136 +ENGINE = INNODB
  22.137 +CHARACTER SET utf8;
  22.138 +
  22.139 +/* 
  22.140 +   Tables for server event statistics
  22.141 +
  22.142 +   Possible statistic keys:
  22.143 +   1=CONNECTIONS     (active connections)
  22.144 +   2=POSTED_NEWS     (directly to the server posted unique messages)
  22.145 +   3=GATEWAYED_NEWS  (posted unique message gateways through the ML-gateway)
  22.146 +   4=FEEDED_NEWS     (unique messages feed via NNTP)
  22.147 +
  22.148 +   The server will create snapshots of the above data.
  22.149 +
  22.150 +   Normalization: 1NF, 2NF
  22.151 +*/
  22.152 +CREATE TABLE events
  22.153 +(
  22.154 +  event_time         BIGINT UNSIGNED,   /* time of this snapshot */
  22.155 +  event_key          TINYINT UNSIGNED,  /* which data */
  22.156 +  group_id           INT REFERENCES groups.group_id ON DELETE CASCADE,
  22.157 +
  22.158 +  PRIMARY KEY(event_time, event_key)
  22.159 +)
  22.160 +ENGINE = INNODB
  22.161 +CHARACTER SET utf8;
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/helpers/database_postgresql8_tmpl.sql	Fri Jun 26 16:48:50 2009 +0200
    23.3 @@ -0,0 +1,138 @@
    23.4 +/*
    23.5 +  Create a database at first:
    23.6 +    CREATE DATABASE sonews ENCODING 'UTF8';
    23.7 +*/
    23.8 +
    23.9 +/* 
   23.10 +  flags:
   23.11 +  If bit 0 is set, groups is a mirrorred mailing list. 
   23.12 +  If not set default newsgroup.
   23.13 +
   23.14 +  Normalization: 1NF, 2NF, 3NF
   23.15 +*/
   23.16 +CREATE TABLE groups 
   23.17 +(
   23.18 +  group_id      SERIAL,
   23.19 +  name          VARCHAR(80) NOT NULL,
   23.20 +  flags         SMALLINT DEFAULT 0,
   23.21 +
   23.22 +  PRIMARY KEY(group_id),
   23.23 +  UNIQUE(name)
   23.24 +);
   23.25 +
   23.26 +CREATE TABLE articles 
   23.27 +(
   23.28 +  article_id    INT,
   23.29 +  body          BYTEA,
   23.30 +
   23.31 +  PRIMARY KEY(article_id)
   23.32 +);
   23.33 +
   23.34 +CREATE TABLE article_ids
   23.35 +(
   23.36 +  article_id  INT REFERENCES articles(article_id) ON DELETE CASCADE,
   23.37 +  message_id  VARCHAR(255),
   23.38 +
   23.39 +  PRIMARY KEY(article_id),
   23.40 +  UNIQUE(message_id)
   23.41 +);
   23.42 +
   23.43 +CREATE TABLE headers
   23.44 +(
   23.45 +  article_id    INT REFERENCES articles(article_id) ON DELETE CASCADE,
   23.46 +  header_key    VARCHAR(255),
   23.47 +  header_value  TEXT,
   23.48 +  header_index  INT,
   23.49 +
   23.50 +  PRIMARY KEY(article_id, header_key, header_index)
   23.51 +);
   23.52 +
   23.53 +/*
   23.54 +  Normalization: 1NF, 2NF
   23.55 +*/
   23.56 +CREATE TABLE postings 
   23.57 +(
   23.58 +  group_id      INTEGER,
   23.59 +  article_id    INTEGER REFERENCES articles (article_id) ON DELETE CASCADE,
   23.60 +  article_index INTEGER NOT NULL, 
   23.61 +
   23.62 +  PRIMARY KEY(group_id, article_id)
   23.63 +);
   23.64 +
   23.65 +/* 
   23.66 +  Table for association of newsgroups and mailing-lists 
   23.67 +
   23.68 +  Normalization: 1NF, 2NF, 3NF
   23.69 +*/
   23.70 +CREATE TABLE groups2list
   23.71 +(
   23.72 +  group_id   INTEGER REFERENCES groups(group_id) ON DELETE CASCADE,
   23.73 +  listaddress VARCHAR(255),
   23.74 +
   23.75 +  PRIMARY KEY(group_id, listaddress),
   23.76 +  UNIQUE(listaddress)
   23.77 +);
   23.78 +
   23.79 +/* 
   23.80 +  Configuration table, containing key/value pairs 
   23.81 +
   23.82 +  Normalization: 1NF, 2NF, 3NF
   23.83 +*/
   23.84 +CREATE TABLE config
   23.85 +(
   23.86 +  config_key     VARCHAR(255),
   23.87 +  config_value   TEXT,
   23.88 +
   23.89 +  PRIMARY KEY(config_key)
   23.90 +);
   23.91 +
   23.92 +/* 
   23.93 +  Newsserver peers 
   23.94 +
   23.95 +  Normalization: 1NF (atomic values), 2NF
   23.96 +*/
   23.97 +CREATE TABLE peers
   23.98 +(
   23.99 +  peer_id     SERIAL,
  23.100 +  host        VARCHAR(255),
  23.101 +  port        SMALLINT,
  23.102 +
  23.103 +  PRIMARY KEY(peer_id),
  23.104 +  UNIQUE(host, port)
  23.105 +);
  23.106 +
  23.107 +/* 
  23.108 +  List of newsgroups to feed into sonews 
  23.109 +
  23.110 +  Normalization: 1NF, 2NF, 3NF
  23.111 +*/
  23.112 +CREATE TABLE peer_subscriptions
  23.113 +(
  23.114 +  peer_id    INTEGER REFERENCES peers (peer_id) ON DELETE CASCADE, 
  23.115 +  group_id   INTEGER REFERENCES groups (group_id) ON DELETE CASCADE,
  23.116 +  feedtype   SMALLINT DEFAULT 0, /* 0: pullfeed; 1: pushfeed */
  23.117 +
  23.118 +  PRIMARY KEY(peer_id, group_id, feedtype)
  23.119 +);
  23.120 +
  23.121 +/* 
  23.122 +   Tables for server event statistics
  23.123 +
  23.124 +   Possible statistic keys:
  23.125 +   1=CONNECTIONS     (active connections)
  23.126 +   2=POSTED_NEWS     (directly to the server posted unique messages)
  23.127 +   3=GATEWAYED_NEWS  (posted unique message gateways through the ML-gateway)
  23.128 +   4=FEEDED_NEWS     (unique messages feed via NNTP)
  23.129 +
  23.130 +   The server will create snapshots of the above data.
  23.131 +
  23.132 +   Normalization: 1NF, 2NF
  23.133 +*/
  23.134 +CREATE TABLE events
  23.135 +(
  23.136 +  event_time         BIGINT,   /* time of this snapshot */
  23.137 +  event_key          SMALLINT,  /* which data */
  23.138 +  group_id           INT REFERENCES groups(group_id) ON DELETE CASCADE,
  23.139 +
  23.140 +  PRIMARY KEY(event_time, event_key)
  23.141 +);
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/helpers/helptext	Fri Jun 26 16:48:50 2009 +0200
    24.3 @@ -0,0 +1,12 @@
    24.4 +Welcome to sonews help system
    24.5 +
    24.6 +Here is a short overview of supported NNTP commands of this newsserver:
    24.7 +
    24.8 +ARTICLE <article-number|message-id>
    24.9 +  Retrieve article including its head
   24.10 +
   24.11 +GROUP <groupname>
   24.12 +  Change currently selected group
   24.13 +
   24.14 +POST
   24.15 +  Post an article to a newsgroup
   24.16 \ No newline at end of file
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/helpers/sonews	Fri Jun 26 16:48:50 2009 +0200
    25.3 @@ -0,0 +1,42 @@
    25.4 +#!/bin/bash
    25.5 +
    25.6 +CLASSPATH=/usr/share/java/sonews.jar:\
    25.7 +/usr/share/java/mysql-connector-java.jar:\
    25.8 +/usr/share/java/glassfish-mail.jar:\
    25.9 +/usr/share/java/postgresql.jar
   25.10 +
   25.11 +LOGFILE=/var/log/sonews.log
   25.12 +PIDFILE=/var/run/sonews.pid
   25.13 +ARGS="-mlgw -c /etc/sonews/sonews.conf -feed"
   25.14 +
   25.15 +MAINCLASS=org.sonews.daemon.Main
   25.16 +JAVA=java
   25.17 +
   25.18 +case "$1" in
   25.19 +  start)
   25.20 +    echo "Starting sonews Newsserver..."
   25.21 +    $JAVA -classpath $CLASSPATH $MAINCLASS $ARGS &> $LOGFILE &
   25.22 +    PID=$!
   25.23 +    echo $PID > $PIDFILE
   25.24 +    ;;
   25.25 +  stop)
   25.26 +    echo "Stopping sonews Newsserver..."
   25.27 +    PID=`cat $PIDFILE`
   25.28 +    STOPRES=0
   25.29 +    while [ $STOPRES -le 0 ]
   25.30 +    do
   25.31 +      kill -15 $PID &> /dev/null
   25.32 +      STOPRES=$?
   25.33 +      sleep 1
   25.34 +    done
   25.35 +    echo "done."
   25.36 +    ;;
   25.37 +  setup)
   25.38 +    $JAVA -classpath $CLASSPATH org.sonews.util.DatabaseSetup
   25.39 +    ;;
   25.40 +  purge)
   25.41 +    $JAVA -classpath $CLASSPATH org.sonews.util.Purger
   25.42 +    ;;
   25.43 +  *)
   25.44 +    echo "Usage: sonews [start|stop|restart|setup|purge]"
   25.45 +esac
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/helpers/sonews-web	Fri Jun 26 16:48:50 2009 +0200
    26.3 @@ -0,0 +1,7 @@
    26.4 +#!/bin/bash
    26.5 +export CLASSPATH=/usr/share/java/jchart2d.jar:/usr/share/java/sonews.jar
    26.6 +ARG0=org.sonews.web.SonewsServlet@sonews
    26.7 +ARG1=org.sonews.web.SonewsConfigServlet@sonews/config
    26.8 +ARG2=org.sonews.web.SonewsPeerServlet@sonews/peer
    26.9 +ARG3=org.sonews.web.SonewsChartServlet@sonews/chart
   26.10 +/usr/bin/kitten -s $ARG0 -s $ARG1 -s $ARG2 -s $ARG3
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/helpers/sonews.conf.sample	Fri Jun 26 16:48:50 2009 +0200
    27.3 @@ -0,0 +1,4 @@
    27.4 +sonews.storage.database=jdbc:mysql://localhost/sonews
    27.5 +sonews.storage.user=sonews
    27.6 +sonews.storage.dbmsdriver=com.mysql.jdbc.Driver
    27.7 +sonews.storage.password=mySecret
    27.8 \ No newline at end of file
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/helpers/usage	Fri Jun 26 16:48:50 2009 +0200
    28.3 @@ -0,0 +1,8 @@
    28.4 +java -jar sonews.jar [arguments]
    28.5 +        where arguments:
    28.6 +    -c|-config         <path to config file> if custom config file preferred
    28.7 +    -dumpjdbcdriver    Prints out a list of available JDBC drivers
    28.8 +    -feed              Enables feed daemon for pulling news from peer servers
    28.9 +    -h|-help           This output
   28.10 +    -mlgw              Enables the Mailinglist Gateway poller
   28.11 +    -useaux            Enables an additional secondary port for listening
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/makedeb	Fri Jun 26 16:48:50 2009 +0200
    29.3 @@ -0,0 +1,45 @@
    29.4 +#!/bin/bash -x
    29.5 +PACKAGE_ROOT=sonews
    29.6 +
    29.7 +# Compile classes 
    29.8 +scons
    29.9 +
   29.10 +# Create JAR files; this cannot be done with SCons,
   29.11 +# because Scons looses inner classes.
   29.12 +jar -cf sonews.jar -C classes/ org/
   29.13 +jar -ufe sonews.jar org.sonews.daemon.Main
   29.14 +jar -cf test.jar -C classes/ test/ 
   29.15 +jar -ufe test.jar test.TestBench
   29.16 +jar -cf sonews-helpers.jar helpers/
   29.17 +jar -uf sonews.jar org/sonews/web/*.tmpl
   29.18 +
   29.19 +# Create faked root for packaging
   29.20 +sudo rm -r $PACKAGE_ROOT/
   29.21 +mkdir -p $PACKAGE_ROOT/usr/share/java
   29.22 +mkdir -p $PACKAGE_ROOT/usr/bin
   29.23 +mkdir -p $PACKAGE_ROOT/etc/sonews
   29.24 +mkdir -p $PACKAGE_ROOT/usr/share/doc/sonews/
   29.25 +cp -r DEBIAN $PACKAGE_ROOT/
   29.26 +cp helpers/sonews $PACKAGE_ROOT/usr/bin/sonews
   29.27 +cp helpers/sonews.conf.sample $PACKAGE_ROOT/etc/sonews/sonews.conf
   29.28 +cp helpers/copyright $PACKAGE_ROOT/usr/share/doc/sonews/
   29.29 +cp sonews*.jar $PACKAGE_ROOT/usr/share/java/
   29.30 +
   29.31 +sudo chown root:root -R $PACKAGE_ROOT/
   29.32 +
   29.33 +dpkg-deb --build $PACKAGE_ROOT
   29.34 +
   29.35 +# Cleanup
   29.36 +sudo rm -r $PACKAGE_ROOT
   29.37 +rm -r classes/
   29.38 +
   29.39 +# Create metapackage sonews-web
   29.40 +PACKAGE_ROOT=sonews-web
   29.41 +mkdir $PACKAGE_ROOT
   29.42 +cp -r DEBIAN-web $PACKAGE_ROOT/DEBIAN
   29.43 +dpkg-deb --build $PACKAGE_ROOT
   29.44 +rm -r $PACKAGE_ROOT
   29.45 +
   29.46 +# Check debs
   29.47 +lintian sonews.deb
   29.48 +lintian sonews-web.deb
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/org/sonews/daemon/AbstractDaemon.java	Fri Jun 26 16:48:50 2009 +0200
    30.3 @@ -0,0 +1,105 @@
    30.4 +/*
    30.5 + *   SONEWS News Server
    30.6 + *   see AUTHORS for the list of contributors
    30.7 + *
    30.8 + *   This program is free software: you can redistribute it and/or modify
    30.9 + *   it under the terms of the GNU General Public License as published by
   30.10 + *   the Free Software Foundation, either version 3 of the License, or
   30.11 + *   (at your option) any later version.
   30.12 + *
   30.13 + *   This program is distributed in the hope that it will be useful,
   30.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   30.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   30.16 + *   GNU General Public License for more details.
   30.17 + *
   30.18 + *   You should have received a copy of the GNU General Public License
   30.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   30.20 + */
   30.21 +
   30.22 +package org.sonews.daemon;
   30.23 +
   30.24 +import java.sql.SQLException;
   30.25 +import org.sonews.daemon.storage.Database;
   30.26 +import org.sonews.util.Log;
   30.27 +
   30.28 +/**
   30.29 + * Base class of all sonews threads.
   30.30 + * Instances of this class will be automatically registered at the ShutdownHook
   30.31 + * to be cleanly exited when the server is forced to exit.
   30.32 + * @author Christian Lins
   30.33 + * @since sonews/0.5.0
   30.34 + */
   30.35 +public abstract class AbstractDaemon extends Thread
   30.36 +{
   30.37 +
   30.38 +  /** This variable is write synchronized through setRunning */
   30.39 +  private boolean isRunning = false;
   30.40 +
   30.41 +  /**
   30.42 +   * Protected constructor. Will be called by derived classes.
   30.43 +   */
   30.44 +  protected AbstractDaemon()
   30.45 +  {
   30.46 +    setDaemon(true); // VM will exit when all threads are daemons
   30.47 +    setName(getClass().getSimpleName());
   30.48 +  }
   30.49 +  
   30.50 +  /**
   30.51 +   * @return true if shutdown() was not yet called.
   30.52 +   */
   30.53 +  public boolean isRunning()
   30.54 +  {
   30.55 +    synchronized(this)
   30.56 +    {
   30.57 +      return this.isRunning;
   30.58 +    }
   30.59 +  }
   30.60 +  
   30.61 +  /**
   30.62 +   * Marks this thread to exit soon. Closes the associated Database connection
   30.63 +   * if available.
   30.64 +   * @throws java.sql.SQLException
   30.65 +   */
   30.66 +  void shutdownNow()
   30.67 +    throws SQLException
   30.68 +  {
   30.69 +    synchronized(this)
   30.70 +    {
   30.71 +      this.isRunning = false;
   30.72 +      Database db = Database.getInstance(false);
   30.73 +      if(db != null)
   30.74 +      {
   30.75 +        db.shutdown();
   30.76 +      }
   30.77 +    }
   30.78 +  }
   30.79 +  
   30.80 +  /**
   30.81 +   * Calls shutdownNow() but catches SQLExceptions if occurring.
   30.82 +   */
   30.83 +  public void shutdown()
   30.84 +  {
   30.85 +    try
   30.86 +    {
   30.87 +      shutdownNow();
   30.88 +    }
   30.89 +    catch(SQLException ex)
   30.90 +    {
   30.91 +      Log.msg(ex, true);
   30.92 +    }
   30.93 +  }
   30.94 +  
   30.95 +  /**
   30.96 +   * Starts this daemon.
   30.97 +   */
   30.98 +  @Override
   30.99 +  public void start()
  30.100 +  {
  30.101 +    synchronized(this)
  30.102 +    {
  30.103 +      this.isRunning = true;
  30.104 +    }
  30.105 +    super.start();
  30.106 +  }
  30.107 +  
  30.108 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/org/sonews/daemon/BootstrapConfig.java	Fri Jun 26 16:48:50 2009 +0200
    31.3 @@ -0,0 +1,194 @@
    31.4 +/*
    31.5 + *   SONEWS News Server
    31.6 + *   see AUTHORS for the list of contributors
    31.7 + *
    31.8 + *   This program is free software: you can redistribute it and/or modify
    31.9 + *   it under the terms of the GNU General Public License as published by
   31.10 + *   the Free Software Foundation, either version 3 of the License, or
   31.11 + *   (at your option) any later version.
   31.12 + *
   31.13 + *   This program is distributed in the hope that it will be useful,
   31.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   31.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   31.16 + *   GNU General Public License for more details.
   31.17 + *
   31.18 + *   You should have received a copy of the GNU General Public License
   31.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   31.20 + */
   31.21 +
   31.22 +package org.sonews.daemon;
   31.23 +
   31.24 +import java.io.FileInputStream;
   31.25 +import java.io.FileNotFoundException;
   31.26 +import java.io.FileOutputStream;
   31.27 +import java.io.IOException;
   31.28 +import java.util.Properties;
   31.29 +import org.sonews.util.AbstractConfig;
   31.30 +
   31.31 +/**
   31.32 + * Manages the bootstrap configuration. It MUST contain all config values
   31.33 + * that are needed to establish a database connection.
   31.34 + * For further configuration values use the Config class instead as that class
   31.35 + * stores its values within the database.
   31.36 + * @author Christian Lins
   31.37 + * @since sonews/0.5.0
   31.38 + */
   31.39 +public final class BootstrapConfig extends AbstractConfig
   31.40 +{
   31.41 +  
   31.42 +  /** Key constant. If value is "true" every I/O is written to logfile 
   31.43 +   * (which is a lot!) 
   31.44 +   */
   31.45 +  public static final String DEBUG              = "sonews.debug";
   31.46 +  
   31.47 +  /** Key constant. Value is classname of the JDBC driver */
   31.48 +  public static final String STORAGE_DBMSDRIVER = "sonews.storage.dbmsdriver";
   31.49 +  
   31.50 +  /** Key constant. Value is JDBC connect String to the database. */
   31.51 +  public static final String STORAGE_DATABASE   = "sonews.storage.database";
   31.52 +  
   31.53 +  /** Key constant. Value is the username for the DBMS. */
   31.54 +  public static final String STORAGE_USER       = "sonews.storage.user";
   31.55 +  
   31.56 +  /** Key constant. Value is the password for the DBMS. */
   31.57 +  public static final String STORAGE_PASSWORD   = "sonews.storage.password";
   31.58 +  
   31.59 +  /** Key constant. Value is the name of the host which is allowed to use the
   31.60 +   *  XDAEMON command; default: "localhost" */
   31.61 +  public static final String XDAEMON_HOST       = "sonews.xdaemon.host";
   31.62 +
   31.63 +  /** The config key for the filename of the logfile */
   31.64 +  public static final String LOGFILE = "sonews.log";
   31.65 +  
   31.66 +  /** The filename of the config file that is loaded on startup */
   31.67 +  public static volatile String FILE               = "sonews.conf";
   31.68 +
   31.69 +  private static final Properties defaultConfig = new Properties();
   31.70 +  
   31.71 +  private static BootstrapConfig instance = null;
   31.72 +  
   31.73 +  static
   31.74 +  {
   31.75 +    // Set some default values
   31.76 +    defaultConfig.setProperty(STORAGE_DATABASE, "jdbc:mysql://localhost/sonews");
   31.77 +    defaultConfig.setProperty(STORAGE_DBMSDRIVER, "com.mysql.jdbc.Driver");
   31.78 +    defaultConfig.setProperty(STORAGE_USER, "sonews_user");
   31.79 +    defaultConfig.setProperty(STORAGE_PASSWORD, "mysecret");
   31.80 +    defaultConfig.setProperty(DEBUG, "false");
   31.81 +  }
   31.82 +  
   31.83 +  /**
   31.84 +   * Note: this method is not thread-safe
   31.85 +   * @return A Config instance
   31.86 +   */
   31.87 +  public static synchronized BootstrapConfig getInstance()
   31.88 +  {
   31.89 +    if(instance == null)
   31.90 +    {
   31.91 +      instance = new BootstrapConfig();
   31.92 +    }
   31.93 +    return instance;
   31.94 +  }
   31.95 +
   31.96 +  // Every config instance is initialized with the default values.
   31.97 +  private final Properties settings = (Properties)defaultConfig.clone();
   31.98 +
   31.99 +  /**
  31.100 +   * Config is a singelton class with only one instance at time.
  31.101 +   * So the constructor is private to prevent the creation of more
  31.102 +   * then one Config instance.
  31.103 +   * @see Config.getInstance() to retrieve an instance of Config
  31.104 +   */
  31.105 +  private BootstrapConfig()
  31.106 +  {
  31.107 +    try
  31.108 +    {
  31.109 +      // Load settings from file
  31.110 +      load();
  31.111 +    }
  31.112 +    catch(IOException ex)
  31.113 +    {
  31.114 +      ex.printStackTrace();
  31.115 +    }
  31.116 +  }
  31.117 +
  31.118 +  /**
  31.119 +   * Loads the configuration from the config file. By default this is done
  31.120 +   * by the (private) constructor but it can be useful to reload the config
  31.121 +   * by invoking this method.
  31.122 +   * @throws IOException
  31.123 +   */
  31.124 +  public void load() 
  31.125 +    throws IOException
  31.126 +  {
  31.127 +    FileInputStream in = null;
  31.128 +    
  31.129 +    try
  31.130 +    {
  31.131 +      in = new FileInputStream(FILE);
  31.132 +      settings.load(in);
  31.133 +    }
  31.134 +    catch (FileNotFoundException e)
  31.135 +    {
  31.136 +      // MUST NOT use Log otherwise endless loop
  31.137 +      System.err.println(e.getMessage());
  31.138 +      save();
  31.139 +    }
  31.140 +    finally
  31.141 +    {
  31.142 +      if(in != null)
  31.143 +        in.close();
  31.144 +    }
  31.145 +  }
  31.146 +
  31.147 +  /**
  31.148 +   * Saves this Config to the config file. By default this is done
  31.149 +   * at program end.
  31.150 +   * @throws FileNotFoundException
  31.151 +   * @throws IOException
  31.152 +   */
  31.153 +  public void save() throws FileNotFoundException, IOException
  31.154 +  {
  31.155 +    FileOutputStream out = null;
  31.156 +    try
  31.157 +    {
  31.158 +      out = new FileOutputStream(FILE);
  31.159 +      settings.store(out, "SONEWS Config File");
  31.160 +      out.flush();
  31.161 +    }
  31.162 +    catch(IOException ex)
  31.163 +    {
  31.164 +      throw ex;
  31.165 +    }
  31.166 +    finally
  31.167 +    {
  31.168 +      if(out != null)
  31.169 +        out.close();
  31.170 +    }
  31.171 +  }
  31.172 +  
  31.173 +  /**
  31.174 +   * Returns the value that is stored within this config
  31.175 +   * identified by the given key. If the key cannot be found
  31.176 +   * the default value is returned.
  31.177 +   * @param key Key to identify the value.
  31.178 +   * @param def The default value that is returned if the key
  31.179 +   * is not found in this Config.
  31.180 +   * @return
  31.181 +   */
  31.182 +  public String get(String key, String def)
  31.183 +  {
  31.184 +    return settings.getProperty(key, def);
  31.185 +  }
  31.186 +
  31.187 +  /**
  31.188 +   * Sets the value for a given key.
  31.189 +   * @param key
  31.190 +   * @param value
  31.191 +   */
  31.192 +  public void set(final String key, final String value)
  31.193 +  {
  31.194 +    settings.setProperty(key, value);
  31.195 +  }
  31.196 +
  31.197 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/org/sonews/daemon/ChannelLineBuffers.java	Fri Jun 26 16:48:50 2009 +0200
    32.3 @@ -0,0 +1,270 @@
    32.4 +/*
    32.5 + *   SONEWS News Server
    32.6 + *   see AUTHORS for the list of contributors
    32.7 + *
    32.8 + *   This program is free software: you can redistribute it and/or modify
    32.9 + *   it under the terms of the GNU General Public License as published by
   32.10 + *   the Free Software Foundation, either version 3 of the License, or
   32.11 + *   (at your option) any later version.
   32.12 + *
   32.13 + *   This program is distributed in the hope that it will be useful,
   32.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   32.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   32.16 + *   GNU General Public License for more details.
   32.17 + *
   32.18 + *   You should have received a copy of the GNU General Public License
   32.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   32.20 + */
   32.21 +
   32.22 +package org.sonews.daemon;
   32.23 +
   32.24 +import java.nio.ByteBuffer;
   32.25 +import java.nio.channels.ClosedChannelException;
   32.26 +import java.util.ArrayList;
   32.27 +import java.util.List;
   32.28 +
   32.29 +/**
   32.30 + * Class holding ByteBuffers for SocketChannels/NNTPConnection.
   32.31 + * Due to the complex nature of AIO/NIO we must properly handle the line 
   32.32 + * buffers for the input and output of the SocketChannels.
   32.33 + * @author Christian Lins
   32.34 + * @since sonews/0.5.0
   32.35 + */
   32.36 +public class ChannelLineBuffers 
   32.37 +{
   32.38 +  
   32.39 +  /**
   32.40 +   * Size of one small buffer; 
   32.41 +   * per default this is 512 bytes to fit one standard line.
   32.42 +   */
   32.43 +  public static final int BUFFER_SIZE = 512;
   32.44 +  
   32.45 +  private static int maxCachedBuffers = 2048; // Cached buffers maximum
   32.46 +  
   32.47 +  private static final List<ByteBuffer> freeSmallBuffers
   32.48 +    = new ArrayList<ByteBuffer>(maxCachedBuffers);
   32.49 +  
   32.50 +  /**
   32.51 +   * Allocates a predefined number of direct ByteBuffers (allocated via
   32.52 +   * ByteBuffer.allocateDirect()). This method is Thread-safe, but should only
   32.53 +   * called at startup.
   32.54 +   */
   32.55 +  public static void allocateDirect()
   32.56 +  {
   32.57 +    synchronized(freeSmallBuffers)
   32.58 +    {
   32.59 +      for(int n = 0; n < maxCachedBuffers; n++)
   32.60 +      {
   32.61 +        ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
   32.62 +        freeSmallBuffers.add(buffer);
   32.63 +      }
   32.64 +    }
   32.65 +  }
   32.66 +  
   32.67 +  private ByteBuffer       inputBuffer   = newLineBuffer();
   32.68 +  private List<ByteBuffer> outputBuffers = new ArrayList<ByteBuffer>();
   32.69 +  
   32.70 +  /**
   32.71 +   * Add the given ByteBuffer to the list of buffers to be send to the client.
   32.72 +   * This method is Thread-safe.
   32.73 +   * @param buffer
   32.74 +   * @throws java.nio.channels.ClosedChannelException If the client channel was
   32.75 +   * already closed.
   32.76 +   */
   32.77 +  public void addOutputBuffer(ByteBuffer buffer)
   32.78 +    throws ClosedChannelException
   32.79 +  {
   32.80 +    if(outputBuffers == null)
   32.81 +    {
   32.82 +      throw new ClosedChannelException();
   32.83 +    }
   32.84 +    
   32.85 +    synchronized(outputBuffers)
   32.86 +    {
   32.87 +      outputBuffers.add(buffer);
   32.88 +    }
   32.89 +  }
   32.90 +  
   32.91 +  /**
   32.92 +   * Currently a channel has only one input buffer. This *may* be a bottleneck
   32.93 +   * and should investigated in the future.
   32.94 +   * @param channel
   32.95 +   * @return The input buffer associated with given channel.
   32.96 +   */
   32.97 +  public ByteBuffer getInputBuffer()
   32.98 +  {
   32.99 +    return inputBuffer;
  32.100 +  }
  32.101 +  
  32.102 +  /**
  32.103 +   * Returns the current output buffer for writing(!) to SocketChannel.
  32.104 +   * @param channel
  32.105 +   * @return The next input buffer that contains unprocessed data or null
  32.106 +   * if the connection was closed or there are no more unprocessed buffers.
  32.107 +   */
  32.108 +  public ByteBuffer getOutputBuffer()
  32.109 +  {
  32.110 +    synchronized(outputBuffers)
  32.111 +    {
  32.112 +      if(outputBuffers == null || outputBuffers.isEmpty())
  32.113 +      {
  32.114 +        return null;
  32.115 +      }
  32.116 +      else
  32.117 +      {
  32.118 +        ByteBuffer buffer = outputBuffers.get(0);
  32.119 +        if(buffer.remaining() == 0)
  32.120 +        {
  32.121 +          outputBuffers.remove(0);
  32.122 +          // Add old buffers to the list of free buffers
  32.123 +          recycleBuffer(buffer);
  32.124 +          buffer = getOutputBuffer();
  32.125 +        }
  32.126 +        return buffer;
  32.127 +      }
  32.128 +    }
  32.129 +  }
  32.130 +  
  32.131 +  /**
  32.132 +   * Goes through the input buffer of the given channel and searches
  32.133 +   * for next line terminator. If a '\n' is found, the bytes up to the
  32.134 +   * line terminator are returned as array of bytes (the line terminator
  32.135 +   * is omitted). If none is found the method returns null.
  32.136 +   * @param channel
  32.137 +   * @return A ByteBuffer wrapping the line.
  32.138 +   */
  32.139 +  ByteBuffer nextInputLine()
  32.140 +  {
  32.141 +    if(inputBuffer == null)
  32.142 +    {
  32.143 +      return null;
  32.144 +    }
  32.145 +    
  32.146 +    synchronized(inputBuffer)
  32.147 +    {
  32.148 +      ByteBuffer buffer = inputBuffer;
  32.149 +
  32.150 +      // Mark the current write position
  32.151 +      int mark = buffer.position();
  32.152 +
  32.153 +      // Set position to 0 and limit to current position
  32.154 +      buffer.flip();
  32.155 +
  32.156 +      ByteBuffer lineBuffer = newLineBuffer();
  32.157 +
  32.158 +      while (buffer.position() < buffer.limit())
  32.159 +      {
  32.160 +        byte b = buffer.get();
  32.161 +        if (b == 10) // '\n'
  32.162 +        {
  32.163 +          // The bytes between the buffer's current position and its limit, 
  32.164 +          // if any, are copied to the beginning of the buffer. That is, the 
  32.165 +          // byte at index p = position() is copied to index zero, the byte at 
  32.166 +          // index p + 1 is copied to index one, and so forth until the byte 
  32.167 +          // at index limit() - 1 is copied to index n = limit() - 1 - p. 
  32.168 +          // The buffer's position is then set to n+1 and its limit is set to 
  32.169 +          // its capacity.
  32.170 +          buffer.compact();
  32.171 +
  32.172 +          lineBuffer.flip(); // limit to position, position to 0
  32.173 +          return lineBuffer;
  32.174 +        }
  32.175 +        else
  32.176 +        {
  32.177 +          lineBuffer.put(b);
  32.178 +        }
  32.179 +      }
  32.180 +
  32.181 +      buffer.limit(BUFFER_SIZE);
  32.182 +      buffer.position(mark);
  32.183 +
  32.184 +      if(buffer.hasRemaining())
  32.185 +      {
  32.186 +        return null;
  32.187 +      }
  32.188 +      else
  32.189 +      {
  32.190 +        // In the first 512 was no newline found, so the input is not standard
  32.191 +        // compliant. We return the current buffer as new line and add a space
  32.192 +        // to the beginning of the next line which corrects some overlong header
  32.193 +        // lines.
  32.194 +        inputBuffer = newLineBuffer();
  32.195 +        inputBuffer.put((byte)' ');
  32.196 +        buffer.flip();
  32.197 +        return buffer;
  32.198 +      }
  32.199 +    }
  32.200 +  }
  32.201 +  
  32.202 +  /**
  32.203 +   * Returns a at least 512 bytes long ByteBuffer ready for usage.
  32.204 +   * The method first try to reuse an already allocated (cached) buffer but
  32.205 +   * if that fails returns a newly allocated direct buffer.
  32.206 +   * Use recycleBuffer() method when you do not longer use the allocated buffer.
  32.207 +   */
  32.208 +  static ByteBuffer newLineBuffer()
  32.209 +  {
  32.210 +    ByteBuffer buf = null;
  32.211 +    synchronized(freeSmallBuffers)
  32.212 +    {
  32.213 +      if(!freeSmallBuffers.isEmpty())
  32.214 +      {
  32.215 +        buf = freeSmallBuffers.remove(0);
  32.216 +      }
  32.217 +    }
  32.218 +      
  32.219 +    if(buf == null)
  32.220 +    {
  32.221 +      // Allocate a non-direct buffer
  32.222 +      buf = ByteBuffer.allocate(BUFFER_SIZE);
  32.223 +    }
  32.224 +    
  32.225 +    assert buf.position() == 0;
  32.226 +    assert buf.limit() >= BUFFER_SIZE;
  32.227 +    
  32.228 +    return buf;
  32.229 +  }
  32.230 +  
  32.231 +  /**
  32.232 +   * Adds the given buffer to the list of free buffers if it is a valuable
  32.233 +   * direct allocated buffer.
  32.234 +   * @param buffer
  32.235 +   */
  32.236 +  public static void recycleBuffer(ByteBuffer buffer)
  32.237 +  {
  32.238 +    assert buffer != null;
  32.239 +    assert buffer.capacity() >= BUFFER_SIZE;
  32.240 +
  32.241 +    if(buffer.isDirect())
  32.242 +    {
  32.243 +      // Add old buffers to the list of free buffers
  32.244 +      synchronized(freeSmallBuffers)
  32.245 +      {
  32.246 +        buffer.clear(); // Set position to 0 and limit to capacity
  32.247 +        freeSmallBuffers.add(buffer);
  32.248 +      }
  32.249 +    } // if(buffer.isDirect())
  32.250 +  }
  32.251 +  
  32.252 +  /**
  32.253 +   * Recycles all buffers of this ChannelLineBuffers object.
  32.254 +   */
  32.255 +  public void recycleBuffers()
  32.256 +  {
  32.257 +    synchronized(inputBuffer)
  32.258 +    {
  32.259 +      recycleBuffer(inputBuffer);
  32.260 +      this.inputBuffer = null;
  32.261 +    }
  32.262 +    
  32.263 +    synchronized(outputBuffers)
  32.264 +    {
  32.265 +      for(ByteBuffer buf : outputBuffers)
  32.266 +      {
  32.267 +        recycleBuffer(buf);
  32.268 +      }
  32.269 +      outputBuffers = null;
  32.270 +    }
  32.271 +  }
  32.272 +  
  32.273 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/org/sonews/daemon/ChannelReader.java	Fri Jun 26 16:48:50 2009 +0200
    33.3 @@ -0,0 +1,202 @@
    33.4 +/*
    33.5 + *   SONEWS News Server
    33.6 + *   see AUTHORS for the list of contributors
    33.7 + *
    33.8 + *   This program is free software: you can redistribute it and/or modify
    33.9 + *   it under the terms of the GNU General Public License as published by
   33.10 + *   the Free Software Foundation, either version 3 of the License, or
   33.11 + *   (at your option) any later version.
   33.12 + *
   33.13 + *   This program is distributed in the hope that it will be useful,
   33.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   33.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   33.16 + *   GNU General Public License for more details.
   33.17 + *
   33.18 + *   You should have received a copy of the GNU General Public License
   33.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   33.20 + */
   33.21 +
   33.22 +package org.sonews.daemon;
   33.23 +
   33.24 +import org.sonews.util.Log;
   33.25 +import java.io.IOException;
   33.26 +import java.nio.ByteBuffer;
   33.27 +import java.nio.channels.CancelledKeyException;
   33.28 +import java.nio.channels.SelectionKey;
   33.29 +import java.nio.channels.Selector;
   33.30 +import java.nio.channels.SocketChannel;
   33.31 +import java.util.Iterator;
   33.32 +import java.util.Set;
   33.33 +
   33.34 +/**
   33.35 + * A Thread task listening for OP_READ events from SocketChannels.
   33.36 + * @author Christian Lins
   33.37 + * @since sonews/0.5.0
   33.38 + */
   33.39 +class ChannelReader extends AbstractDaemon
   33.40 +{
   33.41 +
   33.42 +  private static ChannelReader instance = new ChannelReader();
   33.43 +
   33.44 +  /**
   33.45 +   * @return Active ChannelReader instance.
   33.46 +   */
   33.47 +  public static ChannelReader getInstance()
   33.48 +  {
   33.49 +    return instance;
   33.50 +  }
   33.51 +  
   33.52 +  private Selector selector = null;
   33.53 +  
   33.54 +  protected ChannelReader()
   33.55 +  {
   33.56 +  }
   33.57 +  
   33.58 +  /**
   33.59 +   * Sets the selector which is used by this reader to determine the channel
   33.60 +   * to read from.
   33.61 +   * @param selector
   33.62 +   */
   33.63 +  public void setSelector(final Selector selector)
   33.64 +  {
   33.65 +    this.selector = selector;
   33.66 +  }
   33.67 +  
   33.68 +  /**
   33.69 +   * Run loop. Blocks until some data is available in a channel.
   33.70 +   */
   33.71 +  @Override
   33.72 +  public void run()
   33.73 +  {
   33.74 +    assert selector != null;
   33.75 +
   33.76 +    while(isRunning())
   33.77 +    {
   33.78 +      try
   33.79 +      {
   33.80 +        // select() blocks until some SelectableChannels are ready for
   33.81 +        // processing. There is no need to lock the selector as we have only
   33.82 +        // one thread per selector.
   33.83 +        selector.select();
   33.84 +
   33.85 +        // Get list of selection keys with pending events.
   33.86 +        // Note: the selected key set is not thread-safe
   33.87 +        SocketChannel channel = null;
   33.88 +        NNTPConnection conn = null;
   33.89 +        final Set<SelectionKey> selKeys = selector.selectedKeys();
   33.90 +        SelectionKey selKey = null;
   33.91 +
   33.92 +        synchronized (selKeys)
   33.93 +        {
   33.94 +          Iterator it = selKeys.iterator();
   33.95 +
   33.96 +          // Process the first pending event
   33.97 +          while (it.hasNext())
   33.98 +          {
   33.99 +            selKey = (SelectionKey) it.next();
  33.100 +            channel = (SocketChannel) selKey.channel();
  33.101 +            conn = Connections.getInstance().get(channel);
  33.102 +
  33.103 +            // Because we cannot lock the selKey as that would cause a deadlock
  33.104 +            // we lock the connection. To preserve the order of the received
  33.105 +            // byte blocks a selection key for a connection that has pending
  33.106 +            // read events is skipped.
  33.107 +            if (conn == null || conn.tryReadLock())
  33.108 +            {
  33.109 +              // Remove from set to indicate that it's being processed
  33.110 +              it.remove();
  33.111 +              if (conn != null)
  33.112 +              {
  33.113 +                break; // End while loop
  33.114 +              }
  33.115 +            }
  33.116 +            else
  33.117 +            {
  33.118 +              selKey = null;
  33.119 +              channel = null;
  33.120 +              conn = null;
  33.121 +            }
  33.122 +          }
  33.123 +        }
  33.124 +
  33.125 +        // Do not lock the selKeys while processing because this causes
  33.126 +        // a deadlock in sun.nio.ch.SelectorImpl.lockAndDoSelect()
  33.127 +        if (selKey != null && channel != null && conn != null)
  33.128 +        {
  33.129 +          processSelectionKey(conn, channel, selKey);
  33.130 +          conn.unlockReadLock();
  33.131 +        }
  33.132 +
  33.133 +      }
  33.134 +      catch(CancelledKeyException ex)
  33.135 +      {
  33.136 +        Log.msg("ChannelReader.run(): " + ex, false);
  33.137 +        if(Log.isDebug())
  33.138 +        {
  33.139 +          ex.printStackTrace();
  33.140 +        }
  33.141 +      }
  33.142 +      catch(Exception ex)
  33.143 +      {
  33.144 +        ex.printStackTrace();
  33.145 +      }
  33.146 +      
  33.147 +      // Eventually wait for a register operation
  33.148 +      synchronized (NNTPDaemon.RegisterGate)
  33.149 +      {
  33.150 +      // Do nothing; FindBugs may warn about an empty synchronized 
  33.151 +      // statement, but we cannot use a wait()/notify() mechanism here.
  33.152 +      // If we used something like RegisterGate.wait() we block here
  33.153 +      // until the NNTPDaemon calls notify(). But the daemon only
  33.154 +      // calls notify() if itself is NOT blocked in the listening socket.
  33.155 +      }
  33.156 +    } // while(isRunning())
  33.157 +  }
  33.158 +  
  33.159 +  private void processSelectionKey(final NNTPConnection connection,
  33.160 +    final SocketChannel socketChannel, final SelectionKey selKey)
  33.161 +    throws InterruptedException, IOException
  33.162 +  {
  33.163 +    assert selKey != null;
  33.164 +    assert selKey.isReadable();
  33.165 +    
  33.166 +    // Some bytes are available for reading
  33.167 +    if(selKey.isValid())
  33.168 +    {      
  33.169 +      // Lock the channel
  33.170 +      //synchronized(socketChannel)
  33.171 +      {
  33.172 +        // Read the data into the appropriate buffer
  33.173 +        ByteBuffer buf = connection.getInputBuffer();
  33.174 +        int read = -1;
  33.175 +        try 
  33.176 +        {
  33.177 +          read = socketChannel.read(buf);
  33.178 +        } 
  33.179 +        catch(Exception ex) 
  33.180 +        {
  33.181 +          Log.msg("ChannelReader.processSelectionKey(): " + ex, false);
  33.182 +          if(Log.isDebug())
  33.183 +          {
  33.184 +            ex.printStackTrace();
  33.185 +          }
  33.186 +        }
  33.187 +        
  33.188 +        if(read == -1) // End of stream
  33.189 +        {
  33.190 +          selKey.cancel();
  33.191 +        }
  33.192 +        else if(read > 0) // If some data was read
  33.193 +        {
  33.194 +          ConnectionWorker.addChannel(socketChannel);
  33.195 +        }
  33.196 +      }
  33.197 +    }
  33.198 +    else
  33.199 +    {
  33.200 +      // Should not happen
  33.201 +      Log.msg(selKey, false);
  33.202 +    }
  33.203 +  }
  33.204 +  
  33.205 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/org/sonews/daemon/ChannelWriter.java	Fri Jun 26 16:48:50 2009 +0200
    34.3 @@ -0,0 +1,207 @@
    34.4 +/*
    34.5 + *   SONEWS News Server
    34.6 + *   see AUTHORS for the list of contributors
    34.7 + *
    34.8 + *   This program is free software: you can redistribute it and/or modify
    34.9 + *   it under the terms of the GNU General Public License as published by
   34.10 + *   the Free Software Foundation, either version 3 of the License, or
   34.11 + *   (at your option) any later version.
   34.12 + *
   34.13 + *   This program is distributed in the hope that it will be useful,
   34.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   34.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   34.16 + *   GNU General Public License for more details.
   34.17 + *
   34.18 + *   You should have received a copy of the GNU General Public License
   34.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   34.20 + */
   34.21 +
   34.22 +package org.sonews.daemon;
   34.23 +
   34.24 +import org.sonews.util.Log;
   34.25 +import java.io.IOException;
   34.26 +import java.nio.ByteBuffer;
   34.27 +import java.nio.channels.CancelledKeyException;
   34.28 +import java.nio.channels.SelectionKey;
   34.29 +import java.nio.channels.Selector;
   34.30 +import java.nio.channels.SocketChannel;
   34.31 +import java.util.Iterator;
   34.32 +
   34.33 +/**
   34.34 + * A Thread task that processes OP_WRITE events for SocketChannels.
   34.35 + * @author Christian Lins
   34.36 + * @since sonews/0.5.0
   34.37 + */
   34.38 +class ChannelWriter extends AbstractDaemon
   34.39 +{
   34.40 +
   34.41 +  private static ChannelWriter instance = new ChannelWriter();
   34.42 +
   34.43 +  /**
   34.44 +   * @return Returns the active ChannelWriter instance.
   34.45 +   */
   34.46 +  public static ChannelWriter getInstance()
   34.47 +  {
   34.48 +    return instance;
   34.49 +  }
   34.50 +  
   34.51 +  private Selector selector = null;
   34.52 +  
   34.53 +  protected ChannelWriter()
   34.54 +  {
   34.55 +  }
   34.56 +  
   34.57 +  /**
   34.58 +   * @return Selector associated with this instance.
   34.59 +   */
   34.60 +  public Selector getSelector()
   34.61 +  {
   34.62 +    return this.selector;
   34.63 +  }
   34.64 +  
   34.65 +  /**
   34.66 +   * Sets the selector that is used by this ChannelWriter.
   34.67 +   * @param selector
   34.68 +   */
   34.69 +  public void setSelector(final Selector selector)
   34.70 +  {
   34.71 +    this.selector = selector;
   34.72 +  }
   34.73 +  
   34.74 +  /**
   34.75 +   * Run loop.
   34.76 +   */
   34.77 +  @Override
   34.78 +  public void run()
   34.79 +  {
   34.80 +    assert selector != null;
   34.81 +
   34.82 +    while(isRunning())
   34.83 +    {
   34.84 +      try
   34.85 +      {
   34.86 +        SelectionKey   selKey        = null;
   34.87 +        SocketChannel  socketChannel = null;
   34.88 +        NNTPConnection connection    = null;
   34.89 +
   34.90 +        // select() blocks until some SelectableChannels are ready for
   34.91 +        // processing. There is no need to synchronize the selector as we
   34.92 +        // have only one thread per selector.
   34.93 +        selector.select(); // The return value of select can be ignored
   34.94 +
   34.95 +        // Get list of selection keys with pending OP_WRITE events.
   34.96 +        // The keySET is not thread-safe whereas the keys itself are.
   34.97 +        Iterator it = selector.selectedKeys().iterator();
   34.98 +
   34.99 +        while (it.hasNext())
  34.100 +        {
  34.101 +          // We remove the first event from the set and store it for
  34.102 +          // later processing.
  34.103 +          selKey = (SelectionKey) it.next();
  34.104 +          socketChannel = (SocketChannel) selKey.channel();
  34.105 +          connection = Connections.getInstance().get(socketChannel);
  34.106 +
  34.107 +          it.remove();
  34.108 +          if (connection != null)
  34.109 +          {
  34.110 +            break;
  34.111 +          }
  34.112 +          else
  34.113 +          {
  34.114 +            selKey = null;
  34.115 +          }
  34.116 +        }
  34.117 +        
  34.118 +        if (selKey != null)
  34.119 +        {
  34.120 +          try
  34.121 +          {
  34.122 +            // Process the selected key.
  34.123 +            // As there is only one OP_WRITE key for a given channel, we need
  34.124 +            // not to synchronize this processing to retain the order.
  34.125 +            processSelectionKey(connection, socketChannel, selKey);
  34.126 +          }
  34.127 +          catch (IOException ex)
  34.128 +          {
  34.129 +            Log.msg("Error writing to channel: " + ex, false);
  34.130 +
  34.131 +            // Cancel write events for this channel
  34.132 +            selKey.cancel();
  34.133 +            connection.shutdownInput();
  34.134 +            connection.shutdownOutput();
  34.135 +          }
  34.136 +        }
  34.137 +        
  34.138 +        // Eventually wait for a register operation
  34.139 +        synchronized(NNTPDaemon.RegisterGate) { /* do nothing */ }
  34.140 +      }
  34.141 +      catch(CancelledKeyException ex)
  34.142 +      {
  34.143 +        Log.msg("ChannelWriter.run(): " + ex, true);
  34.144 +      }
  34.145 +      catch(Exception ex)
  34.146 +      {
  34.147 +        ex.printStackTrace();
  34.148 +      }
  34.149 +    } // while(isRunning())
  34.150 +  }
  34.151 +  
  34.152 +  private void processSelectionKey(final NNTPConnection connection,
  34.153 +    final SocketChannel socketChannel, final SelectionKey selKey)
  34.154 +    throws InterruptedException, IOException
  34.155 +  {
  34.156 +    assert connection != null;
  34.157 +    assert socketChannel != null;
  34.158 +    assert selKey != null;
  34.159 +    assert selKey.isWritable();
  34.160 +
  34.161 +    // SocketChannel is ready for writing
  34.162 +    if(selKey.isValid())
  34.163 +    {
  34.164 +      // Lock the socket channel
  34.165 +      synchronized(socketChannel)
  34.166 +      {
  34.167 +        // Get next output buffer
  34.168 +        ByteBuffer buf = connection.getOutputBuffer();
  34.169 +        if(buf == null)
  34.170 +        {
  34.171 +          // Currently we have nothing to write, so we stop the writeable
  34.172 +          // events until we have something to write to the socket channel
  34.173 +          //selKey.cancel();
  34.174 +          selKey.interestOps(0);
  34.175 +          return;
  34.176 +        }
  34.177 + 
  34.178 +        while(buf != null) // There is data to be send
  34.179 +        {
  34.180 +          // Write buffer to socket channel; this method does not block
  34.181 +          if(socketChannel.write(buf) <= 0)
  34.182 +          {
  34.183 +            // Perhaps there is data to be written, but the SocketChannel's
  34.184 +            // buffer is full, so we stop writing to until the next event.
  34.185 +            break;
  34.186 +          }
  34.187 +          else
  34.188 +          {
  34.189 +            // Retrieve next buffer if available; method may return the same
  34.190 +            // buffer instance if it still have some bytes remaining
  34.191 +            buf = connection.getOutputBuffer();
  34.192 +          }
  34.193 +        }
  34.194 +      }
  34.195 +    }
  34.196 +    else
  34.197 +    {
  34.198 +      Log.msg("Invalid OP_WRITE key: " + selKey, false);
  34.199 +
  34.200 +      if (socketChannel.socket().isClosed())
  34.201 +      {
  34.202 +        connection.shutdownInput();
  34.203 +        connection.shutdownOutput();
  34.204 +        socketChannel.close();
  34.205 +        Log.msg("Connection closed.", true);
  34.206 +      }
  34.207 +    }
  34.208 +  }
  34.209 +  
  34.210 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/org/sonews/daemon/Config.java	Fri Jun 26 16:48:50 2009 +0200
    35.3 @@ -0,0 +1,149 @@
    35.4 +/*
    35.5 + *   SONEWS News Server
    35.6 + *   see AUTHORS for the list of contributors
    35.7 + *
    35.8 + *   This program is free software: you can redistribute it and/or modify
    35.9 + *   it under the terms of the GNU General Public License as published by
   35.10 + *   the Free Software Foundation, either version 3 of the License, or
   35.11 + *   (at your option) any later version.
   35.12 + *
   35.13 + *   This program is distributed in the hope that it will be useful,
   35.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   35.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   35.16 + *   GNU General Public License for more details.
   35.17 + *
   35.18 + *   You should have received a copy of the GNU General Public License
   35.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   35.20 + */
   35.21 +
   35.22 +package org.sonews.daemon;
   35.23 +
   35.24 +import org.sonews.util.Log;
   35.25 +import java.sql.SQLException;
   35.26 +import org.sonews.daemon.storage.Database;
   35.27 +import org.sonews.util.AbstractConfig;
   35.28 +import org.sonews.util.TimeoutMap;
   35.29 +
   35.30 +/**
   35.31 + * Provides access to the program wide configuration that is stored within
   35.32 + * the server's database.
   35.33 + * @author Christian Lins
   35.34 + * @since sonews/0.5.0
   35.35 + */
   35.36 +public final class Config extends AbstractConfig
   35.37 +{
   35.38 +
   35.39 +  /** Config key constant. Value is the maximum article size in kilobytes. */
   35.40 +  public static final String ARTICLE_MAXSIZE   = "sonews.article.maxsize";
   35.41 +  
   35.42 +  /** Config key constant. Value: Amount of news that are feeded per run. */
   35.43 +  public static final String FEED_NEWSPERRUN   = "sonews.feed.newsperrun";
   35.44 +  public static final String FEED_PULLINTERVAL = "sonews.feed.pullinterval";
   35.45 +  public static final String HOSTNAME          = "sonews.hostname";
   35.46 +  public static final String PORT              = "sonews.port";
   35.47 +  public static final String TIMEOUT           = "sonews.timeout";
   35.48 +  public static final String MLPOLL_DELETEUNKNOWN = "sonews.mlpoll.deleteunknown";
   35.49 +  public static final String MLPOLL_HOST       = "sonews.mlpoll.host";
   35.50 +  public static final String MLPOLL_PASSWORD   = "sonews.mlpoll.password";
   35.51 +  public static final String MLPOLL_USER       = "sonews.mlpoll.user";
   35.52 +  public static final String MLSEND_ADDRESS    = "sonews.mlsend.address";
   35.53 +  public static final String MLSEND_RW_FROM    = "sonews.mlsend.rewrite.from";
   35.54 +  public static final String MLSEND_RW_SENDER  = "sonews.mlsend.rewrite.sender";
   35.55 +  public static final String MLSEND_HOST       = "sonews.mlsend.host";
   35.56 +  public static final String MLSEND_PASSWORD   = "sonews.mlsend.password";
   35.57 +  public static final String MLSEND_PORT       = "sonews.mlsend.port";
   35.58 +  public static final String MLSEND_USER       = "sonews.mlsend.user";
   35.59 +  
   35.60 +  public static final String[] AVAILABLE_KEYS = {
   35.61 +    Config.ARTICLE_MAXSIZE,
   35.62 +    Config.FEED_NEWSPERRUN,
   35.63 +    Config.FEED_PULLINTERVAL,
   35.64 +    Config.HOSTNAME,
   35.65 +    Config.MLPOLL_DELETEUNKNOWN,
   35.66 +    Config.MLPOLL_HOST,
   35.67 +    Config.MLPOLL_PASSWORD,
   35.68 +    Config.MLPOLL_USER,
   35.69 +    Config.MLSEND_ADDRESS,
   35.70 +    Config.MLSEND_HOST,
   35.71 +    Config.MLSEND_PASSWORD,
   35.72 +    Config.MLSEND_PORT,
   35.73 +    Config.MLSEND_RW_FROM,
   35.74 +    Config.MLSEND_RW_SENDER,
   35.75 +    Config.MLSEND_USER,
   35.76 +    Config.PORT,
   35.77 +    Config.TIMEOUT
   35.78 +  };
   35.79 +
   35.80 +  private static Config instance = new Config();
   35.81 +  
   35.82 +  public static Config getInstance()
   35.83 +  {
   35.84 +    return instance;
   35.85 +  }
   35.86 +  
   35.87 +  private final TimeoutMap<String, String> values 
   35.88 +    = new TimeoutMap<String, String>();
   35.89 +  
   35.90 +  private Config()
   35.91 +  {
   35.92 +    super();
   35.93 +  }
   35.94 +  
   35.95 +  /**
   35.96 +   * Returns the config value for the given key or the defaultValue if the
   35.97 +   * key is not found in config.
   35.98 +   * @param key
   35.99 +   * @param defaultValue
  35.100 +   * @return
  35.101 +   */
  35.102 +  public String get(String key, String defaultValue)
  35.103 +  {
  35.104 +    try
  35.105 +    {
  35.106 +      String configValue = values.get(key);
  35.107 +      if(configValue == null)
  35.108 +      {
  35.109 +        configValue = Database.getInstance().getConfigValue(key);
  35.110 +        if(configValue == null)
  35.111 +        {
  35.112 +          return defaultValue;
  35.113 +        }
  35.114 +        else
  35.115 +        {
  35.116 +          values.put(key, configValue);
  35.117 +          return configValue;
  35.118 +        }
  35.119 +      }
  35.120 +      else
  35.121 +      {
  35.122 +        return configValue;
  35.123 +      }
  35.124 +    }
  35.125 +    catch(SQLException ex)
  35.126 +    {
  35.127 +      Log.msg(ex.getMessage(), false);
  35.128 +      return defaultValue;
  35.129 +    }
  35.130 +  }
  35.131 +  
  35.132 +  /**
  35.133 +   * Sets the config value which is identified by the given key.
  35.134 +   * @param key
  35.135 +   * @param value
  35.136 +   */
  35.137 +  public void set(String key, String value)
  35.138 +  {
  35.139 +    values.put(key, value);
  35.140 +    
  35.141 +    try
  35.142 +    {
  35.143 +      // Write values to database
  35.144 +      Database.getInstance().setConfigValue(key, value);
  35.145 +    }
  35.146 +    catch(SQLException ex)
  35.147 +    {
  35.148 +      ex.printStackTrace();
  35.149 +    }
  35.150 +  }
  35.151 +  
  35.152 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/org/sonews/daemon/ConnectionWorker.java	Fri Jun 26 16:48:50 2009 +0200
    36.3 @@ -0,0 +1,102 @@
    36.4 +/*
    36.5 + *   SONEWS News Server
    36.6 + *   see AUTHORS for the list of contributors
    36.7 + *
    36.8 + *   This program is free software: you can redistribute it and/or modify
    36.9 + *   it under the terms of the GNU General Public License as published by
   36.10 + *   the Free Software Foundation, either version 3 of the License, or
   36.11 + *   (at your option) any later version.
   36.12 + *
   36.13 + *   This program is distributed in the hope that it will be useful,
   36.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   36.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   36.16 + *   GNU General Public License for more details.
   36.17 + *
   36.18 + *   You should have received a copy of the GNU General Public License
   36.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   36.20 + */
   36.21 +
   36.22 +package org.sonews.daemon;
   36.23 +
   36.24 +import org.sonews.util.Log;
   36.25 +import java.nio.ByteBuffer;
   36.26 +import java.nio.channels.SocketChannel;
   36.27 +import java.util.concurrent.ArrayBlockingQueue;
   36.28 +
   36.29 +/**
   36.30 + * Does most of the work: parsing input, talking to client and Database.
   36.31 + * @author Christian Lins
   36.32 + * @since sonews/0.5.0
   36.33 + */
   36.34 +class ConnectionWorker extends AbstractDaemon
   36.35 +{
   36.36 +
   36.37 +  // 256 pending events should be enough
   36.38 +  private static ArrayBlockingQueue<SocketChannel> pendingChannels
   36.39 +    = new ArrayBlockingQueue<SocketChannel>(256, true);
   36.40 +  
   36.41 +  /**
   36.42 +   * Registers the given channel for further event processing.
   36.43 +   * @param channel
   36.44 +   */
   36.45 +  public static void addChannel(SocketChannel channel)
   36.46 +    throws InterruptedException
   36.47 +  {
   36.48 +    pendingChannels.put(channel);
   36.49 +  }
   36.50 +  
   36.51 +  /**
   36.52 +   * Processing loop.
   36.53 +   */
   36.54 +  @Override
   36.55 +  public void run()
   36.56 +  {
   36.57 +    while(isRunning())
   36.58 +    {
   36.59 +      try
   36.60 +      {
   36.61 +        // Retrieve and remove if available, otherwise wait.
   36.62 +        SocketChannel channel = pendingChannels.take();
   36.63 +
   36.64 +        if(channel != null)
   36.65 +        {
   36.66 +          // Connections.getInstance().get() MAY return null
   36.67 +          NNTPConnection conn = Connections.getInstance().get(channel);
   36.68 +          
   36.69 +          // Try to lock the connection object
   36.70 +          if(conn != null && conn.tryReadLock())
   36.71 +          {
   36.72 +            ByteBuffer buf = conn.getBuffers().nextInputLine();
   36.73 +            while(buf != null) // Complete line was received
   36.74 +            {
   36.75 +              final byte[] line = new byte[buf.limit()];
   36.76 +              buf.get(line);
   36.77 +              ChannelLineBuffers.recycleBuffer(buf);
   36.78 +              
   36.79 +              // Here is the actual work done
   36.80 +              conn.lineReceived(line);
   36.81 +
   36.82 +              // Read next line as we could have already received the next line
   36.83 +              buf = conn.getBuffers().nextInputLine();
   36.84 +            }
   36.85 +            conn.unlockReadLock();
   36.86 +          }
   36.87 +          else
   36.88 +          {
   36.89 +            addChannel(channel);
   36.90 +          }
   36.91 +        }
   36.92 +      }
   36.93 +      catch(InterruptedException ex)
   36.94 +      {
   36.95 +        Log.msg("ConnectionWorker interrupted: " + ex, true);
   36.96 +      }
   36.97 +      catch(Exception ex)
   36.98 +      {
   36.99 +        Log.msg("Exception in ConnectionWorker: " + ex, false);
  36.100 +        ex.printStackTrace();
  36.101 +      }
  36.102 +    } // end while(isRunning())
  36.103 +  }
  36.104 +  
  36.105 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/org/sonews/daemon/Connections.java	Fri Jun 26 16:48:50 2009 +0200
    37.3 @@ -0,0 +1,176 @@
    37.4 +/*
    37.5 + *   SONEWS News Server
    37.6 + *   see AUTHORS for the list of contributors
    37.7 + *
    37.8 + *   This program is free software: you can redistribute it and/or modify
    37.9 + *   it under the terms of the GNU General Public License as published by
   37.10 + *   the Free Software Foundation, either version 3 of the License, or
   37.11 + *   (at your option) any later version.
   37.12 + *
   37.13 + *   This program is distributed in the hope that it will be useful,
   37.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   37.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   37.16 + *   GNU General Public License for more details.
   37.17 + *
   37.18 + *   You should have received a copy of the GNU General Public License
   37.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   37.20 + */
   37.21 +
   37.22 +package org.sonews.daemon;
   37.23 +
   37.24 +import org.sonews.util.Log;
   37.25 +import java.io.IOException;
   37.26 +import java.net.InetSocketAddress;
   37.27 +import java.net.Socket;
   37.28 +import java.nio.channels.SocketChannel;
   37.29 +import java.util.ArrayList;
   37.30 +import java.util.HashMap;
   37.31 +import java.util.List;
   37.32 +import java.util.ListIterator;
   37.33 +import java.util.Map;
   37.34 +import org.sonews.util.Stats;
   37.35 +
   37.36 +/**
   37.37 + * Daemon thread collecting all NNTPConnection instances. The thread
   37.38 + * checks periodically if there are stale/timed out connections and
   37.39 + * removes and purges them properly.
   37.40 + * @author Christian Lins
   37.41 + * @since sonews/0.5.0
   37.42 + */
   37.43 +final class Connections extends AbstractDaemon
   37.44 +{
   37.45 +
   37.46 +  private static final Connections instance = new Connections();
   37.47 +  
   37.48 +  /**
   37.49 +   * @return Active Connections instance.
   37.50 +   */
   37.51 +  public static Connections getInstance()
   37.52 +  {
   37.53 +    return Connections.instance;
   37.54 +  }
   37.55 +  
   37.56 +  private final List<NNTPConnection> connections 
   37.57 +    = new ArrayList<NNTPConnection>();
   37.58 +  private final Map<SocketChannel, NNTPConnection> connByChannel 
   37.59 +    = new HashMap<SocketChannel, NNTPConnection>();
   37.60 +  
   37.61 +  private Connections()
   37.62 +  {
   37.63 +    setName("Connections");
   37.64 +  }
   37.65 +  
   37.66 +  /**
   37.67 +   * Adds the given NNTPConnection to the Connections management.
   37.68 +   * @param conn
   37.69 +   * @see org.sonews.daemon.NNTPConnection
   37.70 +   */
   37.71 +  public void add(final NNTPConnection conn)
   37.72 +  {
   37.73 +    synchronized(this.connections)
   37.74 +    {
   37.75 +      this.connections.add(conn);
   37.76 +      this.connByChannel.put(conn.getChannel(), conn);
   37.77 +    }
   37.78 +  }
   37.79 +  
   37.80 +  /**
   37.81 +   * @param channel
   37.82 +   * @return NNTPConnection instance that is associated with the given
   37.83 +   * SocketChannel.
   37.84 +   */
   37.85 +  public NNTPConnection get(final SocketChannel channel)
   37.86 +  {
   37.87 +    synchronized(this.connections)
   37.88 +    {
   37.89 +      return this.connByChannel.get(channel);
   37.90 +    }
   37.91 +  }
   37.92 +
   37.93 +  int getConnectionCount(String remote)
   37.94 +  {
   37.95 +    int cnt = 0;
   37.96 +    synchronized(this.connections)
   37.97 +    {
   37.98 +      for(NNTPConnection conn : this.connections)
   37.99 +      {
  37.100 +        assert conn != null;
  37.101 +        assert conn.getChannel() != null;
  37.102 +
  37.103 +        Socket socket = conn.getChannel().socket();
  37.104 +        if(socket != null)
  37.105 +        {
  37.106 +          InetSocketAddress sockAddr = (InetSocketAddress)socket.getRemoteSocketAddress();
  37.107 +          if(sockAddr != null)
  37.108 +          {
  37.109 +            if(sockAddr.getHostName().equals(remote))
  37.110 +            {
  37.111 +              cnt++;
  37.112 +            }
  37.113 +          }
  37.114 +        } // if(socket != null)
  37.115 +      }
  37.116 +    }
  37.117 +    return cnt;
  37.118 +  }
  37.119 +  
  37.120 +  /**
  37.121 +   * Run loops. Checks periodically for timed out connections and purged them
  37.122 +   * from the lists.
  37.123 +   */
  37.124 +  @Override
  37.125 +  public void run()
  37.126 +  {
  37.127 +    while(isRunning())
  37.128 +    {
  37.129 +      int timeoutMillis = 1000 * Config.getInstance().get(Config.TIMEOUT, 180);
  37.130 +      
  37.131 +      synchronized (this.connections)
  37.132 +      {
  37.133 +        final ListIterator<NNTPConnection> iter = this.connections.listIterator();
  37.134 +        NNTPConnection conn;
  37.135 +
  37.136 +        while (iter.hasNext())
  37.137 +        {
  37.138 +          conn = iter.next();
  37.139 +          if((System.currentTimeMillis() - conn.getLastActivity()) > timeoutMillis)
  37.140 +          {
  37.141 +            // A connection timeout has occurred so purge the connection
  37.142 +            iter.remove();
  37.143 +
  37.144 +            // Close and remove the channel
  37.145 +            SocketChannel channel = conn.getChannel();
  37.146 +            connByChannel.remove(channel);
  37.147 +            
  37.148 +            try
  37.149 +            {
  37.150 +              // Close the channel; implicitely cancels all selectionkeys
  37.151 +              channel.close();
  37.152 +              Log.msg("Disconnected: " + channel.socket().getRemoteSocketAddress() +
  37.153 +                " (timeout)", true);
  37.154 +            }
  37.155 +            catch(IOException ex)
  37.156 +            {
  37.157 +              Log.msg("Connections.run(): " + ex, false);
  37.158 +            }
  37.159 +
  37.160 +            // Recycle the used buffers
  37.161 +            conn.getBuffers().recycleBuffers();
  37.162 +            
  37.163 +            Stats.getInstance().clientDisconnect();
  37.164 +          }
  37.165 +        }
  37.166 +      }
  37.167 +
  37.168 +      try
  37.169 +      {
  37.170 +        Thread.sleep(10000); // Sleep ten seconds
  37.171 +      }
  37.172 +      catch(InterruptedException ex)
  37.173 +      {
  37.174 +        Log.msg("Connections Thread was interrupted: " + ex.getMessage(), false);
  37.175 +      }
  37.176 +    }
  37.177 +  }
  37.178 +  
  37.179 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/org/sonews/daemon/LineEncoder.java	Fri Jun 26 16:48:50 2009 +0200
    38.3 @@ -0,0 +1,80 @@
    38.4 +/*
    38.5 + *   SONEWS News Server
    38.6 + *   see AUTHORS for the list of contributors
    38.7 + *
    38.8 + *   This program is free software: you can redistribute it and/or modify
    38.9 + *   it under the terms of the GNU General Public License as published by
   38.10 + *   the Free Software Foundation, either version 3 of the License, or
   38.11 + *   (at your option) any later version.
   38.12 + *
   38.13 + *   This program is distributed in the hope that it will be useful,
   38.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   38.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   38.16 + *   GNU General Public License for more details.
   38.17 + *
   38.18 + *   You should have received a copy of the GNU General Public License
   38.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   38.20 + */
   38.21 +
   38.22 +package org.sonews.daemon;
   38.23 +
   38.24 +import java.nio.ByteBuffer;
   38.25 +import java.nio.CharBuffer;
   38.26 +import java.nio.channels.ClosedChannelException;
   38.27 +import java.nio.charset.Charset;
   38.28 +import java.nio.charset.CharsetEncoder;
   38.29 +import java.nio.charset.CoderResult;
   38.30 +
   38.31 +/**
   38.32 + * Encodes a line to buffers using the correct charset.
   38.33 + * @author Christian Lins
   38.34 + * @since sonews/0.5.0
   38.35 + */
   38.36 +class LineEncoder
   38.37 +{
   38.38 +
   38.39 +  private CharBuffer    characters;
   38.40 +  private Charset       charset;
   38.41 +  
   38.42 +  /**
   38.43 +   * Constructs new LineEncoder.
   38.44 +   * @param characters
   38.45 +   * @param charset
   38.46 +   */
   38.47 +  public LineEncoder(CharBuffer characters, Charset charset)
   38.48 +  {
   38.49 +    this.characters = characters;
   38.50 +    this.charset    = charset;
   38.51 +  }
   38.52 +  
   38.53 +  /**
   38.54 +   * Encodes the characters of this instance to the given ChannelLineBuffers
   38.55 +   * using the Charset of this instance.
   38.56 +   * @param buffer
   38.57 +   * @throws java.nio.channels.ClosedChannelException
   38.58 +   */
   38.59 +  public void encode(ChannelLineBuffers buffer)
   38.60 +    throws ClosedChannelException
   38.61 +  {
   38.62 +    CharsetEncoder encoder = charset.newEncoder();
   38.63 +    while (characters.hasRemaining())
   38.64 +    {
   38.65 +      ByteBuffer buf = ChannelLineBuffers.newLineBuffer();
   38.66 +      assert buf.position() == 0;
   38.67 +      assert buf.capacity() >= 512;
   38.68 +
   38.69 +      CoderResult res = encoder.encode(characters, buf, true);
   38.70 +
   38.71 +      // Set limit to current position and current position to 0;
   38.72 +      // means make ready for read from buffer
   38.73 +      buf.flip();
   38.74 +      buffer.addOutputBuffer(buf);
   38.75 +
   38.76 +      if (res.isUnderflow()) // All input processed
   38.77 +      {
   38.78 +        break;
   38.79 +      }
   38.80 +    }
   38.81 +  }
   38.82 +  
   38.83 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/org/sonews/daemon/Main.java	Fri Jun 26 16:48:50 2009 +0200
    39.3 @@ -0,0 +1,160 @@
    39.4 +/*
    39.5 + *   SONEWS News Server
    39.6 + *   see AUTHORS for the list of contributors
    39.7 + *
    39.8 + *   This program is free software: you can redistribute it and/or modify
    39.9 + *   it under the terms of the GNU General Public License as published by
   39.10 + *   the Free Software Foundation, either version 3 of the License, or
   39.11 + *   (at your option) any later version.
   39.12 + *
   39.13 + *   This program is distributed in the hope that it will be useful,
   39.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   39.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   39.16 + *   GNU General Public License for more details.
   39.17 + *
   39.18 + *   You should have received a copy of the GNU General Public License
   39.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   39.20 + */
   39.21 +
   39.22 +package org.sonews.daemon;
   39.23 +
   39.24 +import java.sql.Driver;
   39.25 +import java.sql.DriverManager;
   39.26 +import java.sql.SQLException;
   39.27 +import java.util.Enumeration;
   39.28 +import java.util.Date;
   39.29 +import org.sonews.feed.FeedManager;
   39.30 +import org.sonews.mlgw.MailPoller;
   39.31 +import org.sonews.daemon.storage.Database;
   39.32 +import org.sonews.util.Log;
   39.33 +import org.sonews.util.io.Resource;
   39.34 +
   39.35 +/**
   39.36 + * Startup class of the daemon.
   39.37 + * @author Christian Lins
   39.38 + * @since sonews/0.5.0
   39.39 + */
   39.40 +public final class Main
   39.41 +{
   39.42 +  
   39.43 +  private Main()
   39.44 +  {
   39.45 +  }
   39.46 +
   39.47 +  /** Version information of the sonews daemon */
   39.48 +  public static final String VERSION = "sonews/0.5.0";
   39.49 +  public static final Date   STARTDATE = new Date();
   39.50 +  
   39.51 +  /**
   39.52 +   * The main entrypoint.
   39.53 +   * @param args
   39.54 +   * @throws Exception
   39.55 +   */
   39.56 +  public static void main(String[] args) throws Exception
   39.57 +  {
   39.58 +    System.out.println(VERSION);
   39.59 +    Thread.currentThread().setName("Mainthread");
   39.60 +
   39.61 +    // Command line arguments
   39.62 +    boolean feed    = false;  // Enable feeding?
   39.63 +    boolean mlgw    = false;  // Enable Mailinglist gateway?
   39.64 +    int     port    = -1;
   39.65 +    
   39.66 +    for(int n = 0; n < args.length; n++)
   39.67 +    {
   39.68 +      if(args[n].equals("-c") || args[n].equals("-config"))
   39.69 +      {
   39.70 +        BootstrapConfig.FILE = args[++n];
   39.71 +        System.out.println("Using config file " + args[n]);
   39.72 +      }
   39.73 +      else if(args[n].equals("-dumpjdbcdriver"))
   39.74 +      {
   39.75 +        System.out.println("Available JDBC drivers:");
   39.76 +        Enumeration<Driver> drvs =  DriverManager.getDrivers();
   39.77 +        while(drvs.hasMoreElements())
   39.78 +        {
   39.79 +          System.out.println(drvs.nextElement());
   39.80 +        }
   39.81 +        return;
   39.82 +      }
   39.83 +      else if(args[n].equals("-feed"))
   39.84 +      {
   39.85 +        feed = true;
   39.86 +      }
   39.87 +      else if(args[n].equals("-h") || args[n].equals("-help"))
   39.88 +      {
   39.89 +        printArguments();
   39.90 +        return;
   39.91 +      }
   39.92 +      else if(args[n].equals("-mlgw"))
   39.93 +      {
   39.94 +        mlgw = true;
   39.95 +      }
   39.96 +      else if(args[n].equals("-p"))
   39.97 +      {
   39.98 +        port = Integer.parseInt(args[++n]);
   39.99 +      }
  39.100 +    }
  39.101 +    
  39.102 +    // Try to load the Database;
  39.103 +    // Do NOT USE Config or Log classes before this point because they require
  39.104 +    // a working Database connection.
  39.105 +    try
  39.106 +    {
  39.107 +      Database.getInstance();
  39.108 +      
  39.109 +      // Make sure some elementary groups are existing
  39.110 +      if(!Database.getInstance().isGroupExisting("control"))
  39.111 +      {
  39.112 +        Database.getInstance().addGroup("control", 0);
  39.113 +        Log.msg("Group 'control' created.", true);
  39.114 +      }
  39.115 +    }
  39.116 +    catch(SQLException ex)
  39.117 +    {
  39.118 +      ex.printStackTrace();
  39.119 +      System.err.println("Database initialization failed with " + ex.toString());
  39.120 +      System.err.println("Make sure you have specified the correct database" +
  39.121 +        " settings in sonews.conf!");
  39.122 +      return;
  39.123 +    }
  39.124 +    
  39.125 +    ChannelLineBuffers.allocateDirect();
  39.126 +    
  39.127 +    // Add shutdown hook
  39.128 +    Runtime.getRuntime().addShutdownHook(new ShutdownHook());
  39.129 +    
  39.130 +    // Start the listening daemon
  39.131 +    if(port <= 0)
  39.132 +    {
  39.133 +      port = Config.getInstance().get(Config.PORT, 119);
  39.134 +    }
  39.135 +    final NNTPDaemon daemon = NNTPDaemon.createInstance(port);
  39.136 +    daemon.start();
  39.137 +    
  39.138 +    // Start Connections purger thread...
  39.139 +    Connections.getInstance().start();
  39.140 +    
  39.141 +    // Start mailinglist gateway...
  39.142 +    if(mlgw)
  39.143 +    {
  39.144 +      new MailPoller().start();
  39.145 +    }
  39.146 +    
  39.147 +    // Start feeds
  39.148 +    if(feed)
  39.149 +    {
  39.150 +      FeedManager.startFeeding();
  39.151 +    }
  39.152 +    
  39.153 +    // Wait for main thread to exit (setDaemon(false))
  39.154 +    daemon.join();
  39.155 +  }
  39.156 +  
  39.157 +  private static void printArguments()
  39.158 +  {
  39.159 +    String usage = Resource.getAsString("helpers/usage", true);
  39.160 +    System.out.println(usage);
  39.161 +  }
  39.162 +
  39.163 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/org/sonews/daemon/NNTPConnection.java	Fri Jun 26 16:48:50 2009 +0200
    40.3 @@ -0,0 +1,480 @@
    40.4 +/*
    40.5 + *   SONEWS News Server
    40.6 + *   see AUTHORS for the list of contributors
    40.7 + *
    40.8 + *   This program is free software: you can redistribute it and/or modify
    40.9 + *   it under the terms of the GNU General Public License as published by
   40.10 + *   the Free Software Foundation, either version 3 of the License, or
   40.11 + *   (at your option) any later version.
   40.12 + *
   40.13 + *   This program is distributed in the hope that it will be useful,
   40.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   40.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   40.16 + *   GNU General Public License for more details.
   40.17 + *
   40.18 + *   You should have received a copy of the GNU General Public License
   40.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   40.20 + */
   40.21 +
   40.22 +package org.sonews.daemon;
   40.23 +
   40.24 +import org.sonews.util.Log;
   40.25 +import java.io.IOException;
   40.26 +import java.net.InetSocketAddress;
   40.27 +import java.nio.ByteBuffer;
   40.28 +import java.nio.CharBuffer;
   40.29 +import java.nio.channels.ClosedChannelException;
   40.30 +import java.nio.channels.SelectionKey;
   40.31 +import java.nio.channels.SocketChannel;
   40.32 +import java.nio.charset.Charset;
   40.33 +import java.util.Timer;
   40.34 +import java.util.TimerTask;
   40.35 +import org.sonews.daemon.command.ArticleCommand;
   40.36 +import org.sonews.daemon.command.CapabilitiesCommand;
   40.37 +import org.sonews.daemon.command.AbstractCommand;
   40.38 +import org.sonews.daemon.command.GroupCommand;
   40.39 +import org.sonews.daemon.command.HelpCommand;
   40.40 +import org.sonews.daemon.command.ListCommand;
   40.41 +import org.sonews.daemon.command.ListGroupCommand;
   40.42 +import org.sonews.daemon.command.ModeReaderCommand;
   40.43 +import org.sonews.daemon.command.NewGroupsCommand;
   40.44 +import org.sonews.daemon.command.NextPrevCommand;
   40.45 +import org.sonews.daemon.command.OverCommand;
   40.46 +import org.sonews.daemon.command.PostCommand;
   40.47 +import org.sonews.daemon.command.QuitCommand;
   40.48 +import org.sonews.daemon.command.StatCommand;
   40.49 +import org.sonews.daemon.command.UnsupportedCommand;
   40.50 +import org.sonews.daemon.command.XDaemonCommand;
   40.51 +import org.sonews.daemon.command.XPatCommand;
   40.52 +import org.sonews.daemon.storage.Article;
   40.53 +import org.sonews.daemon.storage.Group;
   40.54 +import org.sonews.util.Stats;
   40.55 +
   40.56 +/**
   40.57 + * For every SocketChannel (so TCP/IP connection) there is an instance of
   40.58 + * this class.
   40.59 + * @author Christian Lins
   40.60 + * @since sonews/0.5.0
   40.61 + */
   40.62 +public final class NNTPConnection
   40.63 +{
   40.64 +
   40.65 +  public static final String NEWLINE            = "\r\n";    // RFC defines this as newline
   40.66 +  public static final String MESSAGE_ID_PATTERN = "<[^>]+>";
   40.67 +  
   40.68 +  private static final Timer cancelTimer = new Timer(true); // Thread-safe? True for run as daemon
   40.69 +  
   40.70 +  /** SocketChannel is generally thread-safe */
   40.71 +  private SocketChannel   channel        = null;
   40.72 +  private Charset         charset        = Charset.forName("UTF-8");
   40.73 +  private AbstractCommand command        = null;
   40.74 +  private Article         currentArticle = null;
   40.75 +  private Group           currentGroup   = null;
   40.76 +  private volatile long   lastActivity   = System.currentTimeMillis();
   40.77 +  private ChannelLineBuffers lineBuffers = new ChannelLineBuffers();
   40.78 +  private int             readLock       = 0;
   40.79 +  private final Object    readLockGate   = new Object();
   40.80 +  private SelectionKey    writeSelKey    = null;
   40.81 +  
   40.82 +  public NNTPConnection(final SocketChannel channel)
   40.83 +    throws IOException
   40.84 +  {
   40.85 +    if(channel == null)
   40.86 +    {
   40.87 +      throw new IllegalArgumentException("channel is null");
   40.88 +    }
   40.89 +
   40.90 +    this.channel = channel;
   40.91 +    Stats.getInstance().clientConnect();
   40.92 +  }
   40.93 +  
   40.94 +  /**
   40.95 +   * Tries to get the read lock for this NNTPConnection. This method is Thread-
   40.96 +   * safe and returns true of the read lock was successfully set. If the lock
   40.97 +   * is still hold by another Thread the method returns false.
   40.98 +   */
   40.99 +  boolean tryReadLock()
  40.100 +  {
  40.101 +    // As synchronizing simple types may cause deadlocks,
  40.102 +    // we use a gate object.
  40.103 +    synchronized(readLockGate)
  40.104 +    {
  40.105 +      if(readLock != 0)
  40.106 +      {
  40.107 +        return false;
  40.108 +      }
  40.109 +      else
  40.110 +      {
  40.111 +        readLock = Thread.currentThread().hashCode();
  40.112 +        return true;
  40.113 +      }
  40.114 +    }
  40.115 +  }
  40.116 +  
  40.117 +  /**
  40.118 +   * Releases the read lock in a Thread-safe way.
  40.119 +   * @throws IllegalMonitorStateException if a Thread not holding the lock
  40.120 +   * tries to release it.
  40.121 +   */
  40.122 +  void unlockReadLock()
  40.123 +  {
  40.124 +    synchronized(readLockGate)
  40.125 +    {
  40.126 +      if(readLock == Thread.currentThread().hashCode())
  40.127 +      {
  40.128 +        readLock = 0;
  40.129 +      }
  40.130 +      else
  40.131 +      {
  40.132 +        throw new IllegalMonitorStateException();
  40.133 +      }
  40.134 +    }
  40.135 +  }
  40.136 +  
  40.137 +  /**
  40.138 +   * @return Current input buffer of this NNTPConnection instance.
  40.139 +   */
  40.140 +  public ByteBuffer getInputBuffer()
  40.141 +  {
  40.142 +    return this.lineBuffers.getInputBuffer();
  40.143 +  }
  40.144 +  
  40.145 +  /**
  40.146 +   * @return Output buffer of this NNTPConnection which has at least one byte
  40.147 +   * free storage.
  40.148 +   */
  40.149 +  public ByteBuffer getOutputBuffer()
  40.150 +  {
  40.151 +    return this.lineBuffers.getOutputBuffer();
  40.152 +  }
  40.153 +  
  40.154 +  /**
  40.155 +   * @return ChannelLineBuffers instance associated with this NNTPConnection.
  40.156 +   */
  40.157 +  public ChannelLineBuffers getBuffers()
  40.158 +  {
  40.159 +    return this.lineBuffers;
  40.160 +  }
  40.161 +  
  40.162 +  /**
  40.163 +   * @return true if this connection comes from a local remote address.
  40.164 +   */
  40.165 +  public boolean isLocalConnection()
  40.166 +  {
  40.167 +    return ((InetSocketAddress)this.channel.socket().getRemoteSocketAddress())
  40.168 +      .getHostName().equalsIgnoreCase("localhost");
  40.169 +  }
  40.170 +
  40.171 +  void setWriteSelectionKey(SelectionKey selKey)
  40.172 +  {
  40.173 +    this.writeSelKey = selKey;
  40.174 +  }
  40.175 +
  40.176 +  public void shutdownInput()
  40.177 +  {
  40.178 +    try
  40.179 +    {
  40.180 +      // Closes the input line of the channel's socket, so no new data
  40.181 +      // will be received and a timeout can be triggered.
  40.182 +      this.channel.socket().shutdownInput();
  40.183 +    }
  40.184 +    catch(IOException ex)
  40.185 +    {
  40.186 +      Log.msg("Exception in NNTPConnection.shutdownInput(): " + ex, false);
  40.187 +      if(Log.isDebug())
  40.188 +      {
  40.189 +        ex.printStackTrace();
  40.190 +      }
  40.191 +    }
  40.192 +  }
  40.193 +  
  40.194 +  public void shutdownOutput()
  40.195 +  {
  40.196 +    cancelTimer.schedule(new TimerTask() 
  40.197 +    {
  40.198 +      @Override
  40.199 +      public void run()
  40.200 +      {
  40.201 +        try
  40.202 +        {
  40.203 +          // Closes the output line of the channel's socket.
  40.204 +          channel.socket().shutdownOutput();
  40.205 +          channel.close();
  40.206 +        }
  40.207 +        catch(Exception ex)
  40.208 +        {
  40.209 +          Log.msg("NNTPConnection.shutdownOutput(): " + ex, false);
  40.210 +          if(Log.isDebug())
  40.211 +          {
  40.212 +            ex.printStackTrace();
  40.213 +          }
  40.214 +        }
  40.215 +      }
  40.216 +    }, 3000);
  40.217 +  }
  40.218 +  
  40.219 +  public SocketChannel getChannel()
  40.220 +  {
  40.221 +    return this.channel;
  40.222 +  }
  40.223 +  
  40.224 +  public Article getCurrentArticle()
  40.225 +  {
  40.226 +    return this.currentArticle;
  40.227 +  }
  40.228 +  
  40.229 +  public Charset getCurrentCharset()
  40.230 +  {
  40.231 +    return this.charset;
  40.232 +  }
  40.233 +  
  40.234 +  public Group getCurrentGroup()
  40.235 +  {
  40.236 +    return this.currentGroup;
  40.237 +  }
  40.238 +  
  40.239 +  public void setCurrentArticle(final Article article)
  40.240 +  {
  40.241 +    this.currentArticle = article;
  40.242 +  }
  40.243 +  
  40.244 +  public void setCurrentGroup(final Group group)
  40.245 +  {
  40.246 +    this.currentGroup = group;
  40.247 +  }
  40.248 +  
  40.249 +  public long getLastActivity()
  40.250 +  {
  40.251 +    return this.lastActivity;
  40.252 +  }
  40.253 +  
  40.254 +  /**
  40.255 +   * Due to the readLockGate there is no need to synchronize this method.
  40.256 +   * @param raw
  40.257 +   * @throws IllegalArgumentException if raw is null.
  40.258 +   * @throws IllegalStateException if calling thread does not own the readLock.
  40.259 +   */
  40.260 +  void lineReceived(byte[] raw)
  40.261 +  {
  40.262 +    if(raw == null)
  40.263 +    {
  40.264 +      throw new IllegalArgumentException("raw is null");
  40.265 +    }
  40.266 +    
  40.267 +    if(readLock == 0 || readLock != Thread.currentThread().hashCode())
  40.268 +    {
  40.269 +      throw new IllegalStateException("readLock not properly set");
  40.270 +    }
  40.271 +
  40.272 +    this.lastActivity = System.currentTimeMillis();
  40.273 +    
  40.274 +    String line = new String(raw, this.charset);
  40.275 +    
  40.276 +    // There might be a trailing \r, but trim() is a bad idea
  40.277 +    // as it removes also leading spaces from long header lines.
  40.278 +    if(line.endsWith("\r"))
  40.279 +    {
  40.280 +      line = line.substring(0, line.length() - 1);
  40.281 +    }
  40.282 +    
  40.283 +    Log.msg("<< " + line, true);
  40.284 +    
  40.285 +    if(command == null)
  40.286 +    {
  40.287 +      command = parseCommandLine(line);
  40.288 +      assert command != null;
  40.289 +    }
  40.290 +
  40.291 +    try
  40.292 +    {
  40.293 +      // The command object will process the line we just received
  40.294 +      command.processLine(line);
  40.295 +    }
  40.296 +    catch(ClosedChannelException ex0)
  40.297 +    {
  40.298 +      try
  40.299 +      {
  40.300 +        Log.msg("Connection to " + channel.socket().getRemoteSocketAddress() 
  40.301 +            + " closed: " + ex0, true);
  40.302 +      }
  40.303 +      catch(Exception ex0a)
  40.304 +      {
  40.305 +        ex0a.printStackTrace();
  40.306 +      }
  40.307 +    }
  40.308 +    catch(Exception ex1)
  40.309 +    {
  40.310 +      try
  40.311 +      {
  40.312 +        command = null;
  40.313 +        ex1.printStackTrace();
  40.314 +        println("500 Internal server error");
  40.315 +      }
  40.316 +      catch(Exception ex2)
  40.317 +      {
  40.318 +        ex2.printStackTrace();
  40.319 +      }
  40.320 +    }
  40.321 +
  40.322 +    if(command == null || command.hasFinished())
  40.323 +    {
  40.324 +      command = null;
  40.325 +      charset = Charset.forName("UTF-8"); // Reset to default
  40.326 +    }
  40.327 +  }
  40.328 +  
  40.329 +  /**
  40.330 +   * This method performes several if/elseif constructs to determine the
  40.331 +   * fitting command object. 
  40.332 +   * TODO: This string comparisons are probably slow!
  40.333 +   * @param line
  40.334 +   * @return
  40.335 +   */
  40.336 +  private AbstractCommand parseCommandLine(String line)
  40.337 +  {
  40.338 +    AbstractCommand  cmd    = new UnsupportedCommand(this);
  40.339 +    String   cmdStr = line.split(" ")[0];
  40.340 +    
  40.341 +    if(cmdStr.equalsIgnoreCase("ARTICLE") || 
  40.342 +      cmdStr.equalsIgnoreCase("BODY"))
  40.343 +    {
  40.344 +      cmd = new ArticleCommand(this);
  40.345 +    }
  40.346 +    else if(cmdStr.equalsIgnoreCase("CAPABILITIES"))
  40.347 +    {
  40.348 +      cmd = new CapabilitiesCommand(this);
  40.349 +    }
  40.350 +    else if(cmdStr.equalsIgnoreCase("GROUP"))
  40.351 +    {
  40.352 +      cmd = new GroupCommand(this);
  40.353 +    }
  40.354 +    else if(cmdStr.equalsIgnoreCase("HEAD"))
  40.355 +    {
  40.356 +      cmd = new ArticleCommand(this);
  40.357 +    }
  40.358 +    else if(cmdStr.equalsIgnoreCase("HELP"))
  40.359 +    {
  40.360 +      cmd = new HelpCommand(this);
  40.361 +    }
  40.362 +    else if(cmdStr.equalsIgnoreCase("LIST"))
  40.363 +    {
  40.364 +      cmd = new ListCommand(this);
  40.365 +    }
  40.366 +    else if(cmdStr.equalsIgnoreCase("LISTGROUP"))
  40.367 +    {
  40.368 +      cmd = new ListGroupCommand(this);
  40.369 +    }
  40.370 +    else if(cmdStr.equalsIgnoreCase("MODE"))
  40.371 +    {
  40.372 +      cmd = new ModeReaderCommand(this);
  40.373 +    }
  40.374 +    else if(cmdStr.equalsIgnoreCase("NEWGROUPS"))
  40.375 +    {
  40.376 +      cmd = new NewGroupsCommand(this);
  40.377 +    }
  40.378 +    else if(cmdStr.equalsIgnoreCase("NEXT") ||
  40.379 +      cmdStr.equalsIgnoreCase("PREV"))
  40.380 +    {
  40.381 +      cmd = new NextPrevCommand(this);
  40.382 +    }
  40.383 +    else if(cmdStr.equalsIgnoreCase("OVER") ||
  40.384 +      cmdStr.equalsIgnoreCase("XOVER")) // for compatibility with older RFCs
  40.385 +    {
  40.386 +      cmd = new OverCommand(this);
  40.387 +    }
  40.388 +    else if(cmdStr.equalsIgnoreCase("POST"))
  40.389 +    {
  40.390 +      cmd = new PostCommand(this);
  40.391 +    }
  40.392 +    else if(cmdStr.equalsIgnoreCase("QUIT"))
  40.393 +    {
  40.394 +      cmd = new QuitCommand(this);
  40.395 +    }
  40.396 +    else if(cmdStr.equalsIgnoreCase("STAT"))
  40.397 +    {
  40.398 +      cmd = new StatCommand(this);
  40.399 +    }
  40.400 +    else if(cmdStr.equalsIgnoreCase("XDAEMON"))
  40.401 +    {
  40.402 +      cmd = new XDaemonCommand(this);
  40.403 +    }
  40.404 +    else if(cmdStr.equalsIgnoreCase("XPAT"))
  40.405 +    {
  40.406 +      cmd = new XPatCommand(this);
  40.407 +    }
  40.408 +    
  40.409 +    return cmd;
  40.410 +  }
  40.411 +  
  40.412 +  /**
  40.413 +   * Puts the given line into the output buffer, adds a newline character
  40.414 +   * and returns. The method returns immediately and does not block until
  40.415 +   * the line was sent. If line is longer than 510 octets it is split up in
  40.416 +   * several lines. Each line is terminated by \r\n (NNTPConnection.NEWLINE).
  40.417 +   * @param line
  40.418 +   */
  40.419 +  public void println(final CharSequence line, final Charset charset)
  40.420 +    throws IOException
  40.421 +  {    
  40.422 +    writeToChannel(CharBuffer.wrap(line), charset, line);
  40.423 +    writeToChannel(CharBuffer.wrap(NEWLINE), charset, null);
  40.424 +  }
  40.425 +  
  40.426 +  /**
  40.427 +   * Encodes the given CharBuffer using the given Charset to a bunch of
  40.428 +   * ByteBuffers (each 512 bytes large) and enqueues them for writing at the
  40.429 +   * connected SocketChannel.
  40.430 +   * @throws java.io.IOException
  40.431 +   */
  40.432 +  private void writeToChannel(CharBuffer characters, final Charset charset,
  40.433 +    CharSequence debugLine)
  40.434 +    throws IOException
  40.435 +  {
  40.436 +    if(!charset.canEncode())
  40.437 +    {
  40.438 +      Log.msg("FATAL: Charset " + charset + " cannot encode!", false);
  40.439 +      return;
  40.440 +    }
  40.441 +    
  40.442 +    // Write characters to output buffers
  40.443 +    LineEncoder lenc = new LineEncoder(characters, charset);
  40.444 +    lenc.encode(lineBuffers);
  40.445 +    
  40.446 +    // Enable OP_WRITE events so that the buffers are processed
  40.447 +    try
  40.448 +    {
  40.449 +      this.writeSelKey.interestOps(SelectionKey.OP_WRITE);
  40.450 +      ChannelWriter.getInstance().getSelector().wakeup();
  40.451 +    }
  40.452 +    catch (Exception ex) // CancelledKeyException and ChannelCloseException
  40.453 +    {
  40.454 +      Log.msg("NNTPConnection.writeToChannel(): " + ex, false);
  40.455 +      return;
  40.456 +    }
  40.457 +
  40.458 +    // Update last activity timestamp
  40.459 +    this.lastActivity = System.currentTimeMillis();
  40.460 +    if(debugLine != null)
  40.461 +    {
  40.462 +      Log.msg(">> " + debugLine, true);
  40.463 +    }
  40.464 +  }
  40.465 +  
  40.466 +  public void println(final CharSequence line)
  40.467 +    throws IOException
  40.468 +  {
  40.469 +    println(line, charset);
  40.470 +  }
  40.471 +  
  40.472 +  public void print(final String line)
  40.473 +    throws IOException
  40.474 +  {
  40.475 +    writeToChannel(CharBuffer.wrap(line), charset, line);
  40.476 +  }
  40.477 +  
  40.478 +  public void setCurrentCharset(final Charset charset)
  40.479 +  {
  40.480 +    this.charset = charset;
  40.481 +  }
  40.482 +  
  40.483 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/org/sonews/daemon/NNTPDaemon.java	Fri Jun 26 16:48:50 2009 +0200
    41.3 @@ -0,0 +1,195 @@
    41.4 +/*
    41.5 + *   SONEWS News Server
    41.6 + *   see AUTHORS for the list of contributors
    41.7 + *
    41.8 + *   This program is free software: you can redistribute it and/or modify
    41.9 + *   it under the terms of the GNU General Public License as published by
   41.10 + *   the Free Software Foundation, either version 3 of the License, or
   41.11 + *   (at your option) any later version.
   41.12 + *
   41.13 + *   This program is distributed in the hope that it will be useful,
   41.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   41.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   41.16 + *   GNU General Public License for more details.
   41.17 + *
   41.18 + *   You should have received a copy of the GNU General Public License
   41.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   41.20 + */
   41.21 +
   41.22 +package org.sonews.daemon;
   41.23 +
   41.24 +import org.sonews.util.Log;
   41.25 +import java.io.IOException;
   41.26 +import java.net.BindException;
   41.27 +import java.net.InetSocketAddress;
   41.28 +import java.net.ServerSocket;
   41.29 +import java.nio.channels.CancelledKeyException;
   41.30 +import java.nio.channels.ClosedChannelException;
   41.31 +import java.nio.channels.SelectionKey;
   41.32 +import java.nio.channels.Selector;
   41.33 +import java.nio.channels.ServerSocketChannel;
   41.34 +import java.nio.channels.SocketChannel;
   41.35 +
   41.36 +/**
   41.37 + * NNTP daemon using SelectableChannels.
   41.38 + * @author Christian Lins
   41.39 + * @since sonews/0.5.0
   41.40 + */
   41.41 +public final class NNTPDaemon extends AbstractDaemon
   41.42 +{
   41.43 +
   41.44 +  public static final Object RegisterGate = new Object();
   41.45 +  
   41.46 +  private static NNTPDaemon instance = null;
   41.47 +  
   41.48 +  public static synchronized NNTPDaemon createInstance(int port)
   41.49 +  {
   41.50 +    if(instance == null)
   41.51 +    {
   41.52 +      instance = new NNTPDaemon(port);
   41.53 +      return instance;
   41.54 +    }
   41.55 +    else
   41.56 +    {
   41.57 +      throw new RuntimeException("NNTPDaemon.createInstance() called twice");
   41.58 +    }
   41.59 +  }
   41.60 +  
   41.61 +  private int port;
   41.62 +  
   41.63 +  private NNTPDaemon(final int port)
   41.64 +  {
   41.65 +    Log.msg("Server listening on port " + port, false);
   41.66 +    this.port = port;
   41.67 +  }
   41.68 +
   41.69 +  @Override
   41.70 +  public void run()
   41.71 +  {
   41.72 +    try
   41.73 +    {
   41.74 +      // Create a Selector that handles the SocketChannel multiplexing
   41.75 +      final Selector readSelector  = Selector.open();
   41.76 +      final Selector writeSelector = Selector.open();
   41.77 +      
   41.78 +      // Start working threads
   41.79 +      final int workerThreads = Runtime.getRuntime().availableProcessors() * 4;
   41.80 +      ConnectionWorker[] cworkers = new ConnectionWorker[workerThreads];
   41.81 +      for(int n = 0; n < workerThreads; n++)
   41.82 +      {
   41.83 +        cworkers[n] = new ConnectionWorker();
   41.84 +        cworkers[n].start();
   41.85 +      }
   41.86 +      
   41.87 +      ChannelWriter.getInstance().setSelector(writeSelector);
   41.88 +      ChannelReader.getInstance().setSelector(readSelector);
   41.89 +      ChannelWriter.getInstance().start();
   41.90 +      ChannelReader.getInstance().start();
   41.91 +      
   41.92 +      final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
   41.93 +      serverSocketChannel.configureBlocking(true);  // Set to blocking mode
   41.94 +      
   41.95 +      // Configure ServerSocket; bind to socket...
   41.96 +      final ServerSocket serverSocket = serverSocketChannel.socket();
   41.97 +      serverSocket.bind(new InetSocketAddress(this.port));
   41.98 +      
   41.99 +      while(isRunning())
  41.100 +      {
  41.101 +        SocketChannel socketChannel;
  41.102 +        
  41.103 +        try
  41.104 +        {
  41.105 +          // As we set the server socket channel to blocking mode the accept()
  41.106 +          // method will block.
  41.107 +          socketChannel = serverSocketChannel.accept();
  41.108 +          socketChannel.configureBlocking(false);
  41.109 +          assert socketChannel.isConnected();
  41.110 +          assert socketChannel.finishConnect();
  41.111 +        }
  41.112 +        catch(IOException ex)
  41.113 +        {
  41.114 +          // Under heavy load an IOException "Too many open files may
  41.115 +          // be thrown. It most cases we should slow down the connection
  41.116 +          // accepting, to give the worker threads some time to process work.
  41.117 +          Log.msg("IOException while accepting connection: " + ex.getMessage(), false);
  41.118 +          Log.msg("Connection accepting sleeping for seconds...", true);
  41.119 +          Thread.sleep(5000); // 5 seconds
  41.120 +          continue;
  41.121 +        }
  41.122 +        
  41.123 +        final NNTPConnection conn;
  41.124 +        try
  41.125 +        {
  41.126 +          conn = new NNTPConnection(socketChannel);
  41.127 +          Connections.getInstance().add(conn);
  41.128 +        }
  41.129 +        catch(IOException ex)
  41.130 +        {
  41.131 +          Log.msg(ex.getLocalizedMessage(), false);
  41.132 +          socketChannel.close();
  41.133 +          continue;
  41.134 +        }
  41.135 +        
  41.136 +        try
  41.137 +        {
  41.138 +          SelectionKey selKeyWrite =
  41.139 +            registerSelector(writeSelector, socketChannel, SelectionKey.OP_WRITE);
  41.140 +          registerSelector(readSelector, socketChannel, SelectionKey.OP_READ);
  41.141 +          
  41.142 +          Log.msg("Connected: " + socketChannel.socket().getRemoteSocketAddress(), true);
  41.143 +
  41.144 +          // Set write selection key and send hello to client
  41.145 +          conn.setWriteSelectionKey(selKeyWrite);
  41.146 +          conn.println("200 " + Config.getInstance().get(Config.HOSTNAME, "localhost")
  41.147 +              + " " + Main.VERSION + " news server ready - (posting ok).");
  41.148 +        }
  41.149 +        catch(CancelledKeyException cke)
  41.150 +        {
  41.151 +          Log.msg("CancelledKeyException " + cke.getMessage() + " was thrown: " 
  41.152 +            + socketChannel.socket(), false);
  41.153 +        }
  41.154 +        catch(ClosedChannelException cce)
  41.155 +        {
  41.156 +          Log.msg("ClosedChannelException " + cce.getMessage() + " was thrown: " 
  41.157 +            + socketChannel.socket(), false);
  41.158 +        }
  41.159 +      }
  41.160 +    }
  41.161 +    catch(BindException ex)
  41.162 +    {
  41.163 +      // Could not bind to socket; this is a fatal problem; so perform shutdown
  41.164 +      ex.printStackTrace();
  41.165 +      System.exit(1);
  41.166 +    }
  41.167 +    catch(IOException ex)
  41.168 +    {
  41.169 +      ex.printStackTrace();
  41.170 +    }
  41.171 +    catch(Exception ex)
  41.172 +    {
  41.173 +      ex.printStackTrace();
  41.174 +    }
  41.175 +  }
  41.176 +  
  41.177 +  public static SelectionKey registerSelector(final Selector selector,
  41.178 +    final SocketChannel channel, final int op)
  41.179 +    throws CancelledKeyException, ClosedChannelException
  41.180 +  {
  41.181 +    // Register the selector at the channel, so that it will be notified
  41.182 +    // on the socket's events
  41.183 +    synchronized(RegisterGate)
  41.184 +    {
  41.185 +      // Wakeup the currently blocking reader/writer thread; we have locked
  41.186 +      // the RegisterGate to prevent the awakened thread to block again
  41.187 +      selector.wakeup();
  41.188 +      
  41.189 +      // Lock the selector to prevent the waiting worker threads going into
  41.190 +      // selector.select() which would block the selector.
  41.191 +      synchronized (selector)
  41.192 +      {
  41.193 +        return channel.register(selector, op, null);
  41.194 +      }
  41.195 +    }
  41.196 +  }
  41.197 +  
  41.198 +}
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/org/sonews/daemon/ShutdownHook.java	Fri Jun 26 16:48:50 2009 +0200
    42.3 @@ -0,0 +1,83 @@
    42.4 +/*
    42.5 + *   SONEWS News Server
    42.6 + *   see AUTHORS for the list of contributors
    42.7 + *
    42.8 + *   This program is free software: you can redistribute it and/or modify
    42.9 + *   it under the terms of the GNU General Public License as published by
   42.10 + *   the Free Software Foundation, either version 3 of the License, or
   42.11 + *   (at your option) any later version.
   42.12 + *
   42.13 + *   This program is distributed in the hope that it will be useful,
   42.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   42.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   42.16 + *   GNU General Public License for more details.
   42.17 + *
   42.18 + *   You should have received a copy of the GNU General Public License
   42.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   42.20 + */
   42.21 +
   42.22 +package org.sonews.daemon;
   42.23 +
   42.24 +import java.sql.SQLException;
   42.25 +import java.util.Map;
   42.26 +
   42.27 +/**
   42.28 + * Will force all other threads to shutdown cleanly.
   42.29 + * @author Christian Lins
   42.30 + * @since sonews/0.5.0
   42.31 + */
   42.32 +class ShutdownHook extends Thread
   42.33 +{
   42.34 +
   42.35 +  /**
   42.36 +   * Called when the JVM exits.
   42.37 +   */
   42.38 +  @Override
   42.39 +  public void run()
   42.40 +  {
   42.41 +    System.out.println("sonews: Trying to shutdown all threads...");
   42.42 +
   42.43 +    Map<Thread, StackTraceElement[]> threadsMap = Thread.getAllStackTraces();
   42.44 +    for(Thread thread : threadsMap.keySet())
   42.45 +    {
   42.46 +      // Interrupt the thread if it's a AbstractDaemon
   42.47 +      AbstractDaemon daemon;
   42.48 +      if(thread instanceof AbstractDaemon && thread.isAlive())
   42.49 +      {
   42.50 +        try
   42.51 +        {
   42.52 +          daemon = (AbstractDaemon)thread;
   42.53 +          daemon.shutdownNow();
   42.54 +        }
   42.55 +        catch(SQLException ex)
   42.56 +        {
   42.57 +          System.out.println("sonews: " + ex);
   42.58 +        }
   42.59 +      }
   42.60 +    }
   42.61 +    
   42.62 +    for(Thread thread : threadsMap.keySet())
   42.63 +    {
   42.64 +      AbstractDaemon daemon;
   42.65 +      if(thread instanceof AbstractDaemon && thread.isAlive())
   42.66 +      {
   42.67 +        daemon = (AbstractDaemon)thread;
   42.68 +        System.out.println("sonews: Waiting for " + daemon + " to exit...");
   42.69 +        try
   42.70 +        {
   42.71 +          daemon.join(500);
   42.72 +        }
   42.73 +        catch(InterruptedException ex)
   42.74 +        {
   42.75 +          System.out.println(ex.getLocalizedMessage());
   42.76 +        }
   42.77 +      }
   42.78 +    }
   42.79 +    
   42.80 +    // We have notified all not-sleeping AbstractDaemons of the shutdown;
   42.81 +    // all other threads can be simply purged on VM shutdown
   42.82 +    
   42.83 +    System.out.println("sonews: Clean shutdown.");
   42.84 +  }
   42.85 +  
   42.86 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/org/sonews/daemon/command/AbstractCommand.java	Fri Jun 26 16:48:50 2009 +0200
    43.3 @@ -0,0 +1,87 @@
    43.4 +/*
    43.5 + *   SONEWS News Server
    43.6 + *   see AUTHORS for the list of contributors
    43.7 + *
    43.8 + *   This program is free software: you can redistribute it and/or modify
    43.9 + *   it under the terms of the GNU General Public License as published by
   43.10 + *   the Free Software Foundation, either version 3 of the License, or
   43.11 + *   (at your option) any later version.
   43.12 + *
   43.13 + *   This program is distributed in the hope that it will be useful,
   43.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   43.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   43.16 + *   GNU General Public License for more details.
   43.17 + *
   43.18 + *   You should have received a copy of the GNU General Public License
   43.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   43.20 + */
   43.21 +
   43.22 +package org.sonews.daemon.command;
   43.23 +
   43.24 +import java.io.IOException;
   43.25 +import java.nio.charset.Charset;
   43.26 +import java.sql.SQLException;
   43.27 +import org.sonews.daemon.NNTPConnection;
   43.28 +import org.sonews.daemon.storage.Article;
   43.29 +import org.sonews.daemon.storage.Group;
   43.30 +
   43.31 +/**
   43.32 + * Base class for all command handling classes.
   43.33 + * @author Christian Lins
   43.34 + * @author Dennis Schwerdel
   43.35 + * @since n3tpd/0.1
   43.36 + */
   43.37 +public abstract class AbstractCommand
   43.38 +{
   43.39 +
   43.40 +  protected NNTPConnection connection;
   43.41 +
   43.42 +  public AbstractCommand(final NNTPConnection connection)
   43.43 +  {
   43.44 +    this.connection = connection;
   43.45 +  }
   43.46 +
   43.47 +  protected Article getCurrentArticle()
   43.48 +  {
   43.49 +    return connection.getCurrentArticle();
   43.50 +  }
   43.51 +
   43.52 +  protected Group getCurrentGroup()
   43.53 +  {
   43.54 +    return connection.getCurrentGroup();
   43.55 +  }
   43.56 +
   43.57 +  protected void setCurrentArticle(final Article current)
   43.58 +  {
   43.59 +    connection.setCurrentArticle(current);
   43.60 +  }
   43.61 +
   43.62 +  protected void setCurrentGroup(final Group current)
   43.63 +  {
   43.64 +    connection.setCurrentGroup(current);
   43.65 +  }
   43.66 +  
   43.67 +  public abstract void processLine(String line)
   43.68 +    throws IOException, SQLException;
   43.69 +  
   43.70 +  protected void println(final String line)
   43.71 +    throws IOException
   43.72 +  {
   43.73 +    connection.println(line);
   43.74 +  }
   43.75 +  
   43.76 +  protected void println(final String line, final Charset charset)
   43.77 +    throws IOException
   43.78 +  {
   43.79 +    connection.println(line, charset);
   43.80 +  }
   43.81 +  
   43.82 +  protected void printStatus(final int status, final String msg)
   43.83 +    throws IOException
   43.84 +  {
   43.85 +    println(status + " " + msg);
   43.86 +  }
   43.87 +  
   43.88 +  public abstract boolean hasFinished();
   43.89 +
   43.90 +}
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/org/sonews/daemon/command/ArticleCommand.java	Fri Jun 26 16:48:50 2009 +0200
    44.3 @@ -0,0 +1,164 @@
    44.4 +/*
    44.5 + *   SONEWS News Server
    44.6 + *   see AUTHORS for the list of contributors
    44.7 + *
    44.8 + *   This program is free software: you can redistribute it and/or modify
    44.9 + *   it under the terms of the GNU General Public License as published by
   44.10 + *   the Free Software Foundation, either version 3 of the License, or
   44.11 + *   (at your option) any later version.
   44.12 + *
   44.13 + *   This program is distributed in the hope that it will be useful,
   44.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   44.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   44.16 + *   GNU General Public License for more details.
   44.17 + *
   44.18 + *   You should have received a copy of the GNU General Public License
   44.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   44.20 + */
   44.21 +
   44.22 +package org.sonews.daemon.command;
   44.23 +
   44.24 +import java.io.IOException;
   44.25 +import java.sql.SQLException;
   44.26 +import org.sonews.daemon.storage.Article;
   44.27 +import org.sonews.daemon.NNTPConnection;
   44.28 +import org.sonews.daemon.storage.Group;
   44.29 +
   44.30 +/**
   44.31 + * Class handling the ARTICLE, BODY and HEAD commands.
   44.32 + * @author Christian Lins
   44.33 + * @author Dennis Schwerdel
   44.34 + * @since n3tpd/0.1
   44.35 + */
   44.36 +public class ArticleCommand extends AbstractCommand
   44.37 +{
   44.38 +  
   44.39 +  public ArticleCommand(final NNTPConnection connection)
   44.40 +  {
   44.41 +    super(connection);
   44.42 +  }
   44.43 +
   44.44 +  @Override
   44.45 +  public boolean hasFinished()
   44.46 +  {
   44.47 +    return true;
   44.48 +  }
   44.49 +
   44.50 +  // TODO: Refactor this method to reduce its complexity!
   44.51 +  @Override
   44.52 +  public void processLine(final String line)
   44.53 +    throws IOException
   44.54 +  {
   44.55 +    final String[] command = line.split(" ");
   44.56 +    
   44.57 +    Article article  = null;
   44.58 +    long    artIndex = -1;
   44.59 +    if (command.length == 1)
   44.60 +    {
   44.61 +      article = getCurrentArticle();
   44.62 +      if (article == null)
   44.63 +      {
   44.64 +        printStatus(420, "no current article has been selected");
   44.65 +        return;
   44.66 +      }
   44.67 +    }
   44.68 +    else if (command[1].matches(NNTPConnection.MESSAGE_ID_PATTERN))
   44.69 +    {
   44.70 +      // Message-ID
   44.71 +      article = Article.getByMessageID(command[1]);
   44.72 +      if (article == null)
   44.73 +      {
   44.74 +        printStatus(430, "no such article found");
   44.75 +        return;
   44.76 +      }
   44.77 +    }
   44.78 +    else
   44.79 +    {
   44.80 +      // Message Number
   44.81 +      try
   44.82 +      {
   44.83 +        Group currentGroup = connection.getCurrentGroup();
   44.84 +        if(currentGroup == null)
   44.85 +        {
   44.86 +          printStatus(400, "no group selected");
   44.87 +          return;
   44.88 +        }
   44.89 +        
   44.90 +        artIndex = Long.parseLong(command[1]);
   44.91 +        article  = Article.getByArticleNumber(artIndex, currentGroup);
   44.92 +      }
   44.93 +      catch(NumberFormatException ex)
   44.94 +      {
   44.95 +        ex.printStackTrace();
   44.96 +      }
   44.97 +      catch(SQLException ex)
   44.98 +      {
   44.99 +        ex.printStackTrace();
  44.100 +      }
  44.101 +
  44.102 +      if (article == null)
  44.103 +      {
  44.104 +        printStatus(423, "no such article number in this group");
  44.105 +        return;
  44.106 +      }
  44.107 +      setCurrentArticle(article);
  44.108 +    }
  44.109 +
  44.110 +    if(command[0].equalsIgnoreCase("ARTICLE"))
  44.111 +    {
  44.112 +      printStatus(220, artIndex + " " + article.getMessageID()
  44.113 +          + " article retrieved - head and body follow");
  44.114 +      
  44.115 +      println(article.getHeaderSource());
  44.116 +      
  44.117 +      println("");
  44.118 +      println(article.getBody(), article.getBodyCharset());
  44.119 +      println(".");
  44.120 +    }
  44.121 +    else if(command[0].equalsIgnoreCase("BODY"))
  44.122 +    {
  44.123 +      printStatus(222, artIndex + " " + article.getMessageID() + " body");
  44.124 +      println(article.getBody(), article.getBodyCharset());
  44.125 +      println(".");
  44.126 +    }
  44.127 +    
  44.128 +    /*
  44.129 +     * HEAD: This command is mandatory.
  44.130 +     *
  44.131 +     * Syntax
  44.132 +     *    HEAD message-id
  44.133 +     *    HEAD number
  44.134 +     *    HEAD
  44.135 +     *
  44.136 +     * Responses
  44.137 +     *
  44.138 +     * First form (message-id specified)
  44.139 +     *  221 0|n message-id    Headers follow (multi-line)
  44.140 +     *  430                   No article with that message-id
  44.141 +     *
  44.142 +     * Second form (article number specified)
  44.143 +     *  221 n message-id      Headers follow (multi-line)
  44.144 +     *  412                   No newsgroup selected
  44.145 +     *  423                   No article with that number
  44.146 +     *
  44.147 +     * Third form (current article number used)
  44.148 +     *  221 n message-id      Headers follow (multi-line)
  44.149 +     *  412                   No newsgroup selected
  44.150 +     *  420                   Current article number is invalid
  44.151 +     *
  44.152 +     * Parameters
  44.153 +     *  number        Requested article number
  44.154 +     *  n             Returned article number
  44.155 +     *  message-id    Article message-id
  44.156 +     */
  44.157 +    else if(command[0].equalsIgnoreCase("HEAD"))
  44.158 +    {
  44.159 +      printStatus(221, artIndex + " " + article.getMessageID()
  44.160 +          + " Headers follow (multi-line)");
  44.161 +      
  44.162 +      println(article.getHeaderSource());
  44.163 +      println(".");
  44.164 +    }
  44.165 +  }  
  44.166 +  
  44.167 +}
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/org/sonews/daemon/command/CapabilitiesCommand.java	Fri Jun 26 16:48:50 2009 +0200
    45.3 @@ -0,0 +1,80 @@
    45.4 +/*
    45.5 + *   SONEWS News Server
    45.6 + *   see AUTHORS for the list of contributors
    45.7 + *
    45.8 + *   This program is free software: you can redistribute it and/or modify
    45.9 + *   it under the terms of the GNU General Public License as published by
   45.10 + *   the Free Software Foundation, either version 3 of the License, or
   45.11 + *   (at your option) any later version.
   45.12 + *
   45.13 + *   This program is distributed in the hope that it will be useful,
   45.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   45.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   45.16 + *   GNU General Public License for more details.
   45.17 + *
   45.18 + *   You should have received a copy of the GNU General Public License
   45.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   45.20 + */
   45.21 +
   45.22 +package org.sonews.daemon.command;
   45.23 +
   45.24 +import java.io.IOException;
   45.25 +import org.sonews.daemon.NNTPConnection;
   45.26 +
   45.27 +/**
   45.28 + * <pre>
   45.29 + * The CAPABILITIES command allows a client to determine the
   45.30 + * capabilities of the server at any given time.
   45.31 + *
   45.32 + * This command MAY be issued at any time; the server MUST NOT require
   45.33 + * it to be issued in order to make use of any capability. The response
   45.34 + * generated by this command MAY change during a session because of
   45.35 + * other state information (which, in turn, may be changed by the
   45.36 + * effects of other commands or by external events).  An NNTP client is
   45.37 + * only able to get the current and correct information concerning
   45.38 + * available capabilities at any point during a session by issuing a
   45.39 + * CAPABILITIES command at that point of that session and processing the
   45.40 + * response.
   45.41 + * </pre>
   45.42 + * @author Christian Lins
   45.43 + * @since sonews/0.5.0
   45.44 + */
   45.45 +public class CapabilitiesCommand extends AbstractCommand
   45.46 +{
   45.47 +
   45.48 +  protected static final String[] CAPABILITIES = new String[]
   45.49 +    {
   45.50 +      "VERSION 2", // MUST be the first one; VERSION 2 refers to RFC3977
   45.51 +      "READER",    // Server implements commands for reading
   45.52 +      "POST",      // Server implements POST command
   45.53 +      "OVER"       // Server implements OVER command
   45.54 +    };
   45.55 +  
   45.56 +  public CapabilitiesCommand(final NNTPConnection conn)
   45.57 +  {
   45.58 +    super(conn);
   45.59 +  }
   45.60 +
   45.61 +  /**
   45.62 +   * First called after one call to processLine().
   45.63 +   * @return
   45.64 +   */
   45.65 +  @Override
   45.66 +  public boolean hasFinished()
   45.67 +  {
   45.68 +    return true;
   45.69 +  }
   45.70 +
   45.71 +  @Override
   45.72 +  public void processLine(final String line)
   45.73 +    throws IOException
   45.74 +  {
   45.75 +    printStatus(101, "Capabilities list:");
   45.76 +    for(String cap : CAPABILITIES)
   45.77 +    {
   45.78 +      println(cap);
   45.79 +    }
   45.80 +    println(".");
   45.81 +  }
   45.82 +
   45.83 +}
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/org/sonews/daemon/command/GroupCommand.java	Fri Jun 26 16:48:50 2009 +0200
    46.3 @@ -0,0 +1,90 @@
    46.4 +/*
    46.5 + *   SONEWS News Server
    46.6 + *   see AUTHORS for the list of contributors
    46.7 + *
    46.8 + *   This program is free software: you can redistribute it and/or modify
    46.9 + *   it under the terms of the GNU General Public License as published by
   46.10 + *   the Free Software Foundation, either version 3 of the License, or
   46.11 + *   (at your option) any later version.
   46.12 + *
   46.13 + *   This program is distributed in the hope that it will be useful,
   46.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   46.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   46.16 + *   GNU General Public License for more details.
   46.17 + *
   46.18 + *   You should have received a copy of the GNU General Public License
   46.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   46.20 + */
   46.21 +
   46.22 +package org.sonews.daemon.command;
   46.23 +
   46.24 +import java.io.IOException;
   46.25 +import java.sql.SQLException;
   46.26 +import org.sonews.daemon.NNTPConnection;
   46.27 +import org.sonews.daemon.storage.Group;
   46.28 +
   46.29 +/**
   46.30 + * Class handling the GROUP command.
   46.31 + * <pre>
   46.32 + *  Syntax
   46.33 + *    GROUP group
   46.34 + *
   46.35 + *  Responses
   46.36 + *    211 number low high group     Group successfully selected
   46.37 + *    411                           No such newsgroup
   46.38 + *
   46.39 + *  Parameters
   46.40 + *    group     Name of newsgroup
   46.41 + *    number    Estimated number of articles in the group
   46.42 + *    low       Reported low water mark
   46.43 + *    high      Reported high water mark
   46.44 + * </pre>
   46.45 + * (from RFC 3977)
   46.46 + * 
   46.47 + * @author Christian Lins
   46.48 + * @author Dennis Schwerdel
   46.49 + * @since n3tpd/0.1
   46.50 + */
   46.51 +public class GroupCommand extends AbstractCommand
   46.52 +{
   46.53 +
   46.54 +  public GroupCommand(final NNTPConnection conn)
   46.55 +  {
   46.56 +    super(conn);
   46.57 +  }
   46.58 +
   46.59 +  @Override
   46.60 +  public boolean hasFinished()
   46.61 +  {
   46.62 +    return true;
   46.63 +  }
   46.64 +  
   46.65 +  @Override
   46.66 +  public void processLine(final String line)
   46.67 +    throws IOException, SQLException
   46.68 +  {
   46.69 +    final String[] command = line.split(" ");
   46.70 +
   46.71 +    Group group;
   46.72 +    if(command.length >= 2)
   46.73 +    {
   46.74 +      group = Group.getByName(command[1]);
   46.75 +      if(group == null)
   46.76 +      {
   46.77 +        printStatus(411, "no such news group");
   46.78 +      }
   46.79 +      else
   46.80 +      {
   46.81 +        setCurrentGroup(group);
   46.82 +
   46.83 +        printStatus(211, group.getPostingsCount() + " " + group.getFirstArticleNumber() 
   46.84 +          + " " + group.getLastArticleNumber() + " " + group.getName() + " group selected");
   46.85 +      }
   46.86 +    }
   46.87 +    else
   46.88 +    {
   46.89 +      printStatus(500, "no group name given");
   46.90 +    }
   46.91 +  }
   46.92 +
   46.93 +}
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/org/sonews/daemon/command/HelpCommand.java	Fri Jun 26 16:48:50 2009 +0200
    47.3 @@ -0,0 +1,63 @@
    47.4 +/*
    47.5 + *   SONEWS News Server
    47.6 + *   see AUTHORS for the list of contributors
    47.7 + *
    47.8 + *   This program is free software: you can redistribute it and/or modify
    47.9 + *   it under the terms of the GNU General Public License as published by
   47.10 + *   the Free Software Foundation, either version 3 of the License, or
   47.11 + *   (at your option) any later version.
   47.12 + *
   47.13 + *   This program is distributed in the hope that it will be useful,
   47.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   47.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   47.16 + *   GNU General Public License for more details.
   47.17 + *
   47.18 + *   You should have received a copy of the GNU General Public License
   47.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   47.20 + */
   47.21 +
   47.22 +package org.sonews.daemon.command;
   47.23 +
   47.24 +import java.io.IOException;
   47.25 +import org.sonews.daemon.NNTPConnection;
   47.26 +import org.sonews.util.io.Resource;
   47.27 +
   47.28 +/**
   47.29 + * This command provides a short summary of the commands that are
   47.30 + * understood by this implementation of the server.  The help text will
   47.31 + * be presented as a multi-line data block following the 100 response
   47.32 + * code (taken from RFC).
   47.33 + * @author Christian Lins
   47.34 + * @since sonews/0.5.0
   47.35 + */
   47.36 +public class HelpCommand extends AbstractCommand
   47.37 +{
   47.38 +  
   47.39 +  public HelpCommand(final NNTPConnection conn)
   47.40 +  {
   47.41 +    super(conn);
   47.42 +  }
   47.43 +
   47.44 +  @Override
   47.45 +  public boolean hasFinished()
   47.46 +  {
   47.47 +    return true;
   47.48 +  }
   47.49 +  
   47.50 +  @Override
   47.51 +  public void processLine(final String line)
   47.52 +    throws IOException
   47.53 +  {
   47.54 +    printStatus(100, "help text follows");
   47.55 +    
   47.56 +    final String[] help = Resource
   47.57 +      .getAsString("helpers/helptext", true).split("\n");
   47.58 +    for(String hstr : help)
   47.59 +    {
   47.60 +      println(hstr);
   47.61 +    }
   47.62 +    
   47.63 +    println(".");
   47.64 +  }
   47.65 +  
   47.66 +}
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/org/sonews/daemon/command/ListCommand.java	Fri Jun 26 16:48:50 2009 +0200
    48.3 @@ -0,0 +1,109 @@
    48.4 +/*
    48.5 + *   SONEWS News Server
    48.6 + *   see AUTHORS for the list of contributors
    48.7 + *
    48.8 + *   This program is free software: you can redistribute it and/or modify
    48.9 + *   it under the terms of the GNU General Public License as published by
   48.10 + *   the Free Software Foundation, either version 3 of the License, or
   48.11 + *   (at your option) any later version.
   48.12 + *
   48.13 + *   This program is distributed in the hope that it will be useful,
   48.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   48.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   48.16 + *   GNU General Public License for more details.
   48.17 + *
   48.18 + *   You should have received a copy of the GNU General Public License
   48.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   48.20 + */
   48.21 +
   48.22 +package org.sonews.daemon.command;
   48.23 +
   48.24 +import java.io.IOException;
   48.25 +import java.sql.SQLException;
   48.26 +import java.util.List;
   48.27 +import org.sonews.daemon.NNTPConnection;
   48.28 +import org.sonews.daemon.storage.Group;
   48.29 +
   48.30 +/**
   48.31 + * Class handling the LIST command.
   48.32 + * @author Christian Lins
   48.33 + * @author Dennis Schwerdel
   48.34 + * @since n3tpd/0.1
   48.35 + */
   48.36 +public class ListCommand extends AbstractCommand
   48.37 +{
   48.38 +
   48.39 +  public ListCommand(final NNTPConnection conn)
   48.40 +  {
   48.41 +    super(conn);
   48.42 +  }
   48.43 +
   48.44 +  @Override
   48.45 +  public boolean hasFinished()
   48.46 +  {
   48.47 +    return true;
   48.48 +  }
   48.49 +  
   48.50 +  @Override
   48.51 +  public void processLine(final String line)
   48.52 +    throws IOException, SQLException
   48.53 +  {
   48.54 +    final String[] command = line.split(" ");
   48.55 +    
   48.56 +    if (command.length >= 2)
   48.57 +    {
   48.58 +      if (command[1].equalsIgnoreCase("OVERVIEW.FMT"))
   48.59 +      {
   48.60 +        printStatus(215, "information follows");
   48.61 +        println("Subject:\nFrom:\nDate:\nMessage-ID:\nReferences:\nBytes:\nLines:\nXref");
   48.62 +        println(".");
   48.63 +      }
   48.64 +      else if (command[1].equalsIgnoreCase("NEWSGROUPS"))
   48.65 +      {
   48.66 +        printStatus(215, "information follows");
   48.67 +        final List<Group> list = Group.getAll();
   48.68 +        for (Group g : list)
   48.69 +        {
   48.70 +          println(g.getName() + "\t" + "-");
   48.71 +        }
   48.72 +        println(".");
   48.73 +      }
   48.74 +      else if (command[1].equalsIgnoreCase("SUBSCRIPTIONS"))
   48.75 +      {
   48.76 +        printStatus(215, "information follows");
   48.77 +        println(".");
   48.78 +      }
   48.79 +      else if (command[1].equalsIgnoreCase("EXTENSIONS"))
   48.80 +      {
   48.81 +        printStatus(202, "Supported NNTP extensions.");
   48.82 +        println("LISTGROUP");
   48.83 +        println(".");
   48.84 + 
   48.85 +      }
   48.86 +      else
   48.87 +      {
   48.88 +        printStatus(500, "unknown argument to LIST command");
   48.89 +      }
   48.90 +    }
   48.91 +    else
   48.92 +    {
   48.93 +      final List<Group> groups = Group.getAll();
   48.94 +      if(groups != null)
   48.95 +      {
   48.96 +        printStatus(215, "list of newsgroups follows");
   48.97 +        for (Group g : groups)
   48.98 +        {
   48.99 +          // Indeed first the higher article number then the lower
  48.100 +          println(g.getName() + " " + g.getLastArticleNumber() + " "
  48.101 +              + g.getFirstArticleNumber() + " y");
  48.102 +        }
  48.103 +        println(".");
  48.104 +      }
  48.105 +      else
  48.106 +      {
  48.107 +        printStatus(500, "server database malfunction");
  48.108 +      }
  48.109 +    }
  48.110 +  }
  48.111 +
  48.112 +}
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/org/sonews/daemon/command/ListGroupCommand.java	Fri Jun 26 16:48:50 2009 +0200
    49.3 @@ -0,0 +1,81 @@
    49.4 +/*
    49.5 + *   SONEWS News Server
    49.6 + *   see AUTHORS for the list of contributors
    49.7 + *
    49.8 + *   This program is free software: you can redistribute it and/or modify
    49.9 + *   it under the terms of the GNU General Public License as published by
   49.10 + *   the Free Software Foundation, either version 3 of the License, or
   49.11 + *   (at your option) any later version.
   49.12 + *
   49.13 + *   This program is distributed in the hope that it will be useful,
   49.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   49.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   49.16 + *   GNU General Public License for more details.
   49.17 + *
   49.18 + *   You should have received a copy of the GNU General Public License
   49.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   49.20 + */
   49.21 +
   49.22 +package org.sonews.daemon.command;
   49.23 +
   49.24 +import java.io.IOException;
   49.25 +import java.sql.SQLException;
   49.26 +import java.util.List;
   49.27 +import org.sonews.daemon.NNTPConnection;
   49.28 +import org.sonews.daemon.storage.Group;
   49.29 +
   49.30 +/**
   49.31 + * Class handling the LISTGROUP command.
   49.32 + * @author Christian Lins
   49.33 + * @author Dennis Schwerdel
   49.34 + * @since n3tpd/0.1
   49.35 + */
   49.36 +public class ListGroupCommand extends AbstractCommand
   49.37 +{
   49.38 +
   49.39 +  public ListGroupCommand(final NNTPConnection conn)
   49.40 +  {
   49.41 +    super(conn);
   49.42 +  }
   49.43 +
   49.44 +  @Override
   49.45 +  public boolean hasFinished()
   49.46 +  {
   49.47 +    return true;
   49.48 +  }
   49.49 +
   49.50 +  @Override
   49.51 +  public void processLine(final String commandName) 
   49.52 +    throws IOException, SQLException
   49.53 +  {
   49.54 +    final String[] command = commandName.split(" ");
   49.55 +
   49.56 +    Group group;
   49.57 +    if(command.length >= 2)
   49.58 +    {
   49.59 +      group = Group.getByName(command[1]);
   49.60 +    }
   49.61 +    else
   49.62 +    {
   49.63 +      group = getCurrentGroup();
   49.64 +    }
   49.65 +
   49.66 +    if (group == null)
   49.67 +    {
   49.68 +      printStatus(412, "no group selected; use GROUP <group> command");
   49.69 +      return;
   49.70 +    }
   49.71 +
   49.72 +    List<Long> ids = group.getArticleNumbers();
   49.73 +    printStatus(211, ids.size() + " " +
   49.74 +      group.getFirstArticleNumber() + " " + 
   49.75 +      group.getLastArticleNumber() + " list of article numbers follow");
   49.76 +    for(long id : ids)
   49.77 +    {
   49.78 +      // One index number per line
   49.79 +      println(Long.toString(id));
   49.80 +    }
   49.81 +    println(".");
   49.82 +  }
   49.83 +
   49.84 +}
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/org/sonews/daemon/command/ModeReaderCommand.java	Fri Jun 26 16:48:50 2009 +0200
    50.3 @@ -0,0 +1,58 @@
    50.4 +/*
    50.5 + *   SONEWS News Server
    50.6 + *   see AUTHORS for the list of contributors
    50.7 + *
    50.8 + *   This program is free software: you can redistribute it and/or modify
    50.9 + *   it under the terms of the GNU General Public License as published by
   50.10 + *   the Free Software Foundation, either version 3 of the License, or
   50.11 + *   (at your option) any later version.
   50.12 + *
   50.13 + *   This program is distributed in the hope that it will be useful,
   50.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   50.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   50.16 + *   GNU General Public License for more details.
   50.17 + *
   50.18 + *   You should have received a copy of the GNU General Public License
   50.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   50.20 + */
   50.21 +
   50.22 +package org.sonews.daemon.command;
   50.23 +
   50.24 +import java.io.IOException;
   50.25 +import java.sql.SQLException;
   50.26 +import org.sonews.daemon.NNTPConnection;
   50.27 +
   50.28 +/**
   50.29 + * Class handling the MODE READER command. This command actually does nothing
   50.30 + * but returning a success status code.
   50.31 + * @author Christian Lins
   50.32 + * @since sonews/0.5.0
   50.33 + */
   50.34 +public class ModeReaderCommand extends AbstractCommand
   50.35 +{
   50.36 +
   50.37 +  public ModeReaderCommand(final NNTPConnection conn)
   50.38 +  {
   50.39 +    super(conn);
   50.40 +  }
   50.41 +  
   50.42 +  @Override
   50.43 +  public boolean hasFinished()
   50.44 +  {
   50.45 +    return true;
   50.46 +  }
   50.47 +
   50.48 +  @Override
   50.49 +  public void processLine(final String line) throws IOException, SQLException
   50.50 +  {
   50.51 +    if(line.equalsIgnoreCase("MODE READER"))
   50.52 +    {
   50.53 +      printStatus(200, "hello you can post");
   50.54 +    }
   50.55 +    else
   50.56 +    {
   50.57 +      printStatus(500, "I do not know this mode command");
   50.58 +    }
   50.59 +  }
   50.60 +
   50.61 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/org/sonews/daemon/command/NewGroupsCommand.java	Fri Jun 26 16:48:50 2009 +0200
    51.3 @@ -0,0 +1,65 @@
    51.4 +/*
    51.5 + *   SONEWS News Server
    51.6 + *   see AUTHORS for the list of contributors
    51.7 + *
    51.8 + *   This program is free software: you can redistribute it and/or modify
    51.9 + *   it under the terms of the GNU General Public License as published by
   51.10 + *   the Free Software Foundation, either version 3 of the License, or
   51.11 + *   (at your option) any later version.
   51.12 + *
   51.13 + *   This program is distributed in the hope that it will be useful,
   51.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   51.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   51.16 + *   GNU General Public License for more details.
   51.17 + *
   51.18 + *   You should have received a copy of the GNU General Public License
   51.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   51.20 + */
   51.21 +
   51.22 +package org.sonews.daemon.command;
   51.23 +
   51.24 +import java.io.IOException;
   51.25 +import java.sql.SQLException;
   51.26 +import org.sonews.daemon.NNTPConnection;
   51.27 +
   51.28 +/**
   51.29 + * Class handling the NEWGROUPS command.
   51.30 + * @author Christian Lins
   51.31 + * @author Dennis Schwerdel
   51.32 + * @since n3tpd/0.1
   51.33 + */
   51.34 +public class NewGroupsCommand extends AbstractCommand
   51.35 +{
   51.36 +
   51.37 +  public NewGroupsCommand(final NNTPConnection conn)
   51.38 +  {
   51.39 +    super(conn);
   51.40 +  }
   51.41 +
   51.42 +  @Override
   51.43 +  public boolean hasFinished()
   51.44 +  {
   51.45 +    return true;
   51.46 +  }
   51.47 +
   51.48 +  @Override
   51.49 +  public void processLine(final String line)
   51.50 +    throws IOException, SQLException
   51.51 +  {
   51.52 +    final String[] command = line.split(" ");
   51.53 +
   51.54 +    if(command.length == 3)
   51.55 +    {
   51.56 +      printStatus(231, "list of new newsgroups follows");
   51.57 +
   51.58 +      // Currently we do not store a group's creation date;
   51.59 +      // so we return an empty list which is a valid response
   51.60 +      println(".");
   51.61 +    }
   51.62 +    else
   51.63 +    {
   51.64 +      printStatus(500, "invalid command usage");
   51.65 +    }
   51.66 +  }
   51.67 +
   51.68 +}
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/org/sonews/daemon/command/NextPrevCommand.java	Fri Jun 26 16:48:50 2009 +0200
    52.3 @@ -0,0 +1,100 @@
    52.4 +/*
    52.5 + *   SONEWS News Server
    52.6 + *   see AUTHORS for the list of contributors
    52.7 + *
    52.8 + *   This program is free software: you can redistribute it and/or modify
    52.9 + *   it under the terms of the GNU General Public License as published by
   52.10 + *   the Free Software Foundation, either version 3 of the License, or
   52.11 + *   (at your option) any later version.
   52.12 + *
   52.13 + *   This program is distributed in the hope that it will be useful,
   52.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   52.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   52.16 + *   GNU General Public License for more details.
   52.17 + *
   52.18 + *   You should have received a copy of the GNU General Public License
   52.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   52.20 + */
   52.21 +
   52.22 +package org.sonews.daemon.command;
   52.23 +
   52.24 +import java.io.IOException;
   52.25 +import java.sql.SQLException;
   52.26 +import org.sonews.daemon.NNTPConnection;
   52.27 +import org.sonews.daemon.storage.Article;
   52.28 +import org.sonews.daemon.storage.Group;
   52.29 +
   52.30 +/**
   52.31 + * Class handling the NEXT and LAST command.
   52.32 + * @author Christian Lins
   52.33 + * @author Dennis Schwerdel
   52.34 + * @since n3tpd/0.1
   52.35 + */
   52.36 +public class NextPrevCommand extends AbstractCommand
   52.37 +{
   52.38 +
   52.39 +  public NextPrevCommand(final NNTPConnection conn)
   52.40 +  {
   52.41 +    super(conn);
   52.42 +  }
   52.43 +
   52.44 +  @Override
   52.45 +  public boolean hasFinished()
   52.46 +  {
   52.47 +    return true;
   52.48 +  }
   52.49 +
   52.50 +  @Override
   52.51 +  public void processLine(final String line)
   52.52 +    throws IOException, SQLException
   52.53 +  {
   52.54 +    final Article currA = getCurrentArticle();
   52.55 +    final Group   currG = getCurrentGroup();
   52.56 +    
   52.57 +    if (currA == null)
   52.58 +    {
   52.59 +      printStatus(420, "no current article has been selected");
   52.60 +      return;
   52.61 +    }
   52.62 +    
   52.63 +    if (currG == null)
   52.64 +    {
   52.65 +      printStatus(412, "no newsgroup selected");
   52.66 +      return;
   52.67 +    }
   52.68 +    
   52.69 +    final String[] command = line.split(" ");
   52.70 +
   52.71 +    if(command[0].equalsIgnoreCase("NEXT"))
   52.72 +    {
   52.73 +      selectNewArticle(currA, currG, 1);
   52.74 +    }
   52.75 +    else if(command[0].equalsIgnoreCase("PREV"))
   52.76 +    {
   52.77 +      selectNewArticle(currA, currG, -1);
   52.78 +    }
   52.79 +    else
   52.80 +    {
   52.81 +      printStatus(500, "internal server error");
   52.82 +    }
   52.83 +  }
   52.84 +  
   52.85 +  private void selectNewArticle(Article article, Group grp, final int delta)
   52.86 +    throws IOException, SQLException
   52.87 +  {
   52.88 +    assert article != null;
   52.89 +
   52.90 +    article = Article.getByArticleNumber(article.getIndexInGroup(grp) + delta, grp);
   52.91 +
   52.92 +    if(article == null)
   52.93 +    {
   52.94 +      printStatus(421, "no next article in this group");
   52.95 +    }
   52.96 +    else
   52.97 +    {
   52.98 +      setCurrentArticle(article);
   52.99 +      printStatus(223, article.getIndexInGroup(getCurrentGroup()) + " " + article.getMessageID() + " article retrieved - request text separately");
  52.100 +    }
  52.101 +  }
  52.102 +
  52.103 +}
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/org/sonews/daemon/command/OverCommand.java	Fri Jun 26 16:48:50 2009 +0200
    53.3 @@ -0,0 +1,281 @@
    53.4 +/*
    53.5 + *   SONEWS News Server
    53.6 + *   see AUTHORS for the list of contributors
    53.7 + *
    53.8 + *   This program is free software: you can redistribute it and/or modify
    53.9 + *   it under the terms of the GNU General Public License as published by
   53.10 + *   the Free Software Foundation, either version 3 of the License, or
   53.11 + *   (at your option) any later version.
   53.12 + *
   53.13 + *   This program is distributed in the hope that it will be useful,
   53.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   53.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   53.16 + *   GNU General Public License for more details.
   53.17 + *
   53.18 + *   You should have received a copy of the GNU General Public License
   53.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   53.20 + */
   53.21 +
   53.22 +package org.sonews.daemon.command;
   53.23 +
   53.24 +import java.io.IOException;
   53.25 +import java.sql.SQLException;
   53.26 +import java.util.List;
   53.27 +import org.sonews.util.Log;
   53.28 +import org.sonews.daemon.NNTPConnection;
   53.29 +import org.sonews.daemon.storage.Article;
   53.30 +import org.sonews.daemon.storage.ArticleHead;
   53.31 +import org.sonews.daemon.storage.Headers;
   53.32 +import org.sonews.util.Pair;
   53.33 +
   53.34 +/**
   53.35 + * Class handling the OVER/XOVER command.
   53.36 + * 
   53.37 + * Description of the XOVER command:
   53.38 + * <pre>
   53.39 + * XOVER [range]
   53.40 + *
   53.41 + * The XOVER command returns information from the overview
   53.42 + * database for the article(s) specified.
   53.43 + *
   53.44 + * The optional range argument may be any of the following:
   53.45 + *              an article number
   53.46 + *              an article number followed by a dash to indicate
   53.47 + *                 all following
   53.48 + *              an article number followed by a dash followed by
   53.49 + *                 another article number
   53.50 + *
   53.51 + * If no argument is specified, then information from the
   53.52 + * current article is displayed. Successful responses start
   53.53 + * with a 224 response followed by the overview information
   53.54 + * for all matched messages. Once the output is complete, a
   53.55 + * period is sent on a line by itself. If no argument is
   53.56 + * specified, the information for the current article is
   53.57 + * returned.  A news group must have been selected earlier,
   53.58 + * else a 412 error response is returned. If no articles are
   53.59 + * in the range specified, a 420 error response is returned
   53.60 + * by the server. A 502 response will be returned if the
   53.61 + * client only has permission to transfer articles.
   53.62 + *
   53.63 + * Each line of output will be formatted with the article number,
   53.64 + * followed by each of the headers in the overview database or the
   53.65 + * article itself (when the data is not available in the overview
   53.66 + * database) for that article separated by a tab character.  The
   53.67 + * sequence of fields must be in this order: subject, author,
   53.68 + * date, message-id, references, byte count, and line count. Other
   53.69 + * optional fields may follow line count. Other optional fields may
   53.70 + * follow line count. These fields are specified by examining the
   53.71 + * response to the LIST OVERVIEW.FMT command. Where no data exists,
   53.72 + * a null field must be provided (i.e. the output will have two tab
   53.73 + * characters adjacent to each other). Servers should not output
   53.74 + * fields for articles that have been removed since the XOVER database
   53.75 + * was created.
   53.76 + *
   53.77 + * The LIST OVERVIEW.FMT command should be implemented if XOVER
   53.78 + * is implemented. A client can use LIST OVERVIEW.FMT to determine
   53.79 + * what optional fields  and in which order all fields will be
   53.80 + * supplied by the XOVER command. 
   53.81 + *
   53.82 + * Note that any tab and end-of-line characters in any header
   53.83 + * data that is returned will be converted to a space character.
   53.84 + *
   53.85 + * Responses:
   53.86 + *
   53.87 + *   224 Overview information follows
   53.88 + *   412 No news group current selected
   53.89 + *   420 No article(s) selected
   53.90 + *   502 no permission
   53.91 + *
   53.92 + * OVER defines additional responses:
   53.93 + *
   53.94 + *  First form (message-id specified)
   53.95 + *    224    Overview information follows (multi-line)
   53.96 + *    430    No article with that message-id
   53.97 + *
   53.98 + *  Second form (range specified)
   53.99 + *    224    Overview information follows (multi-line)
  53.100 + *    412    No newsgroup selected
  53.101 + *    423    No articles in that range
  53.102 + *
  53.103 + *  Third form (current article number used)
  53.104 + *    224    Overview information follows (multi-line)
  53.105 + *    412    No newsgroup selected
  53.106 + *    420    Current article number is invalid
  53.107 + *
  53.108 + * </pre>
  53.109 + * @author Christian Lins
  53.110 + * @since sonews/0.5.0
  53.111 + */
  53.112 +public class OverCommand extends AbstractCommand
  53.113 +{
  53.114 +
  53.115 +  public static final int MAX_LINES_PER_DBREQUEST = 100;
  53.116 +  
  53.117 +  public OverCommand(final NNTPConnection conn)
  53.118 +  {
  53.119 +    super(conn);
  53.120 +  }
  53.121 +
  53.122 +  @Override
  53.123 +  public boolean hasFinished()
  53.124 +  {
  53.125 +    return true;
  53.126 +  }
  53.127 +
  53.128 +  @Override
  53.129 +  public void processLine(final String line)
  53.130 +    throws IOException, SQLException
  53.131 +  {
  53.132 +    if(getCurrentGroup() == null)
  53.133 +    {
  53.134 +      printStatus(412, "No news group current selected");
  53.135 +    }
  53.136 +    else
  53.137 +    {
  53.138 +      String[] command = line.split(" ");
  53.139 +
  53.140 +      // If no parameter was specified, show information about
  53.141 +      // the currently selected article(s)
  53.142 +      if(command.length == 1)
  53.143 +      {
  53.144 +        final Article art = getCurrentArticle();
  53.145 +        if(art == null)
  53.146 +        {
  53.147 +          printStatus(420, "No article(s) selected");
  53.148 +          return;
  53.149 +        }
  53.150 +
  53.151 +        println(buildOverview(art, -1));
  53.152 +      }
  53.153 +      // otherwise print information about the specified range
  53.154 +      else
  53.155 +      {
  53.156 +        int artStart;
  53.157 +        int artEnd   = getCurrentGroup().getLastArticleNumber();
  53.158 +        String[] nums = command[1].split("-");
  53.159 +        if(nums.length >= 1)
  53.160 +        {
  53.161 +          try
  53.162 +          {
  53.163 +            artStart = Integer.parseInt(nums[0]);
  53.164 +          }
  53.165 +          catch(NumberFormatException e) 
  53.166 +          {
  53.167 +            Log.msg(e.getMessage(), true);
  53.168 +            artStart = Integer.parseInt(command[1]);
  53.169 +          }
  53.170 +        }
  53.171 +        else
  53.172 +        {
  53.173 +          artStart = getCurrentGroup().getFirstArticleNumber();
  53.174 +        }
  53.175 +
  53.176 +        if(nums.length >=2)
  53.177 +        {
  53.178 +          try
  53.179 +          {
  53.180 +            artEnd = Integer.parseInt(nums[1]);
  53.181 +          }
  53.182 +          catch(NumberFormatException e) 
  53.183 +          {
  53.184 +            e.printStackTrace();
  53.185 +          }
  53.186 +        }
  53.187 +
  53.188 +        if(artStart > artEnd)
  53.189 +        {
  53.190 +          if(command[0].equalsIgnoreCase("OVER"))
  53.191 +          {
  53.192 +            printStatus(423, "No articles in that range");
  53.193 +          }
  53.194 +          else
  53.195 +          {
  53.196 +            printStatus(224, "(empty) overview information follows:");
  53.197 +            println(".");
  53.198 +          }
  53.199 +        }
  53.200 +        else
  53.201 +        {
  53.202 +          for(int n = artStart; n <= artEnd; n += MAX_LINES_PER_DBREQUEST)
  53.203 +          {
  53.204 +            int nEnd = Math.min(n + MAX_LINES_PER_DBREQUEST - 1, artEnd);
  53.205 +            List<Pair<Long, ArticleHead>> articleHeads = getCurrentGroup()
  53.206 +              .getArticleHeads(n, nEnd);
  53.207 +            if(articleHeads.isEmpty() && n == artStart
  53.208 +              && command[0].equalsIgnoreCase("OVER"))
  53.209 +            {
  53.210 +              // This reply is only valid for OVER, not for XOVER command
  53.211 +              printStatus(423, "No articles in that range");
  53.212 +              return;
  53.213 +            }
  53.214 +            else if(n == artStart)
  53.215 +            {
  53.216 +              // XOVER replies this although there is no data available
  53.217 +              printStatus(224, "Overview information follows");
  53.218 +            }
  53.219 +
  53.220 +            for(Pair<Long, ArticleHead> article : articleHeads)
  53.221 +            {
  53.222 +              String overview = buildOverview(article.getB(), article.getA());
  53.223 +              println(overview);
  53.224 +            }
  53.225 +          } // for
  53.226 +          println(".");
  53.227 +        }
  53.228 +      }
  53.229 +    }
  53.230 +  }
  53.231 +  
  53.232 +  private String buildOverview(ArticleHead art, long nr)
  53.233 +  {
  53.234 +    StringBuilder overview = new StringBuilder();
  53.235 +    overview.append(nr);
  53.236 +    overview.append('\t');
  53.237 +
  53.238 +    String subject = art.getHeader(Headers.SUBJECT)[0];
  53.239 +    if("".equals(subject))
  53.240 +    {
  53.241 +      subject = "<empty>";
  53.242 +    }
  53.243 +    overview.append(escapeString(subject));
  53.244 +    overview.append('\t');
  53.245 +
  53.246 +    overview.append(escapeString(art.getHeader(Headers.FROM)[0]));
  53.247 +    overview.append('\t');
  53.248 +    overview.append(escapeString(art.getHeader(Headers.DATE)[0]));
  53.249 +    overview.append('\t');
  53.250 +    overview.append(escapeString(art.getHeader(Headers.MESSAGE_ID)[0]));
  53.251 +    overview.append('\t');
  53.252 +    overview.append(escapeString(art.getHeader(Headers.REFERENCES)[0]));
  53.253 +    overview.append('\t');
  53.254 +
  53.255 +    String bytes = art.getHeader(Headers.BYTES)[0];
  53.256 +    if("".equals(bytes))
  53.257 +    {
  53.258 +      bytes = "0";
  53.259 +    }
  53.260 +    overview.append(escapeString(bytes));
  53.261 +    overview.append('\t');
  53.262 +
  53.263 +    String lines = art.getHeader(Headers.LINES)[0];
  53.264 +    if("".equals(lines))
  53.265 +    {
  53.266 +      lines = "0";
  53.267 +    }
  53.268 +    overview.append(escapeString(lines));
  53.269 +    overview.append('\t');
  53.270 +    overview.append(escapeString(art.getHeader(Headers.XREF)[0]));
  53.271 +
  53.272 +    // Remove trailing tabs if some data is empty
  53.273 +    return overview.toString().trim();
  53.274 +  }
  53.275 +  
  53.276 +  private String escapeString(String str)
  53.277 +  {
  53.278 +    String nstr = str.replace("\r", "");
  53.279 +    nstr = nstr.replace('\n', ' ');
  53.280 +    nstr = nstr.replace('\t', ' ');
  53.281 +    return nstr.trim();
  53.282 +  }
  53.283 +  
  53.284 +}
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/org/sonews/daemon/command/PostCommand.java	Fri Jun 26 16:48:50 2009 +0200
    54.3 @@ -0,0 +1,350 @@
    54.4 +/*
    54.5 + *   SONEWS News Server
    54.6 + *   see AUTHORS for the list of contributors
    54.7 + *
    54.8 + *   This program is free software: you can redistribute it and/or modify
    54.9 + *   it under the terms of the GNU General Public License as published by
   54.10 + *   the Free Software Foundation, either version 3 of the License, or
   54.11 + *   (at your option) any later version.
   54.12 + *
   54.13 + *   This program is distributed in the hope that it will be useful,
   54.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   54.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   54.16 + *   GNU General Public License for more details.
   54.17 + *
   54.18 + *   You should have received a copy of the GNU General Public License
   54.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   54.20 + */
   54.21 +
   54.22 +package org.sonews.daemon.command;
   54.23 +
   54.24 +import java.io.IOException;
   54.25 +
   54.26 +import java.io.ByteArrayInputStream;
   54.27 +import java.nio.charset.Charset;
   54.28 +import java.nio.charset.IllegalCharsetNameException;
   54.29 +import java.nio.charset.UnsupportedCharsetException;
   54.30 +import java.sql.SQLException;
   54.31 +import java.util.Locale;
   54.32 +import javax.mail.MessagingException;
   54.33 +import javax.mail.internet.AddressException;
   54.34 +import javax.mail.internet.InternetHeaders;
   54.35 +import org.sonews.daemon.Config;
   54.36 +import org.sonews.util.Log;
   54.37 +import org.sonews.mlgw.Dispatcher;
   54.38 +import org.sonews.daemon.storage.Article;
   54.39 +import org.sonews.daemon.storage.Database;
   54.40 +import org.sonews.daemon.storage.Group;
   54.41 +import org.sonews.daemon.NNTPConnection;
   54.42 +import org.sonews.daemon.storage.Headers;
   54.43 +import org.sonews.feed.FeedManager;
   54.44 +import org.sonews.util.Stats;
   54.45 +
   54.46 +/**
   54.47 + * Implementation of the POST command. This command requires multiple lines
   54.48 + * from the client, so the handling of asynchronous reading is a little tricky
   54.49 + * to handle.
   54.50 + * @author Christian Lins
   54.51 + * @since sonews/0.5.0
   54.52 + */
   54.53 +public class PostCommand extends AbstractCommand
   54.54 +{
   54.55 +  
   54.56 +  private final Article article   = new Article();
   54.57 +  private int           lineCount = 0;
   54.58 +  private long          bodySize  = 0;
   54.59 +  private InternetHeaders headers = null;
   54.60 +  private long          maxBodySize  = 
   54.61 +    Config.getInstance().get(Config.ARTICLE_MAXSIZE, 128) * 1024L; // Size in bytes
   54.62 +  private PostState     state     = PostState.WaitForLineOne;
   54.63 +  private final StringBuilder strBody   = new StringBuilder();
   54.64 +  private final StringBuilder strHead   = new StringBuilder();
   54.65 +  
   54.66 +  public PostCommand(final NNTPConnection conn)
   54.67 +  {
   54.68 +    super(conn);
   54.69 +  }
   54.70 +
   54.71 +  @Override
   54.72 +  public boolean hasFinished()
   54.73 +  {
   54.74 +    return this.state == PostState.Finished;
   54.75 +  }
   54.76 +
   54.77 +  /**
   54.78 +   * Process the given line String. line.trim() was called by NNTPConnection.
   54.79 +   * @param line
   54.80 +   * @throws java.io.IOException
   54.81 +   * @throws java.sql.SQLException
   54.82 +   */
   54.83 +  @Override // TODO: Refactor this method to reduce complexity!
   54.84 +  public void processLine(String line)
   54.85 +    throws IOException, SQLException
   54.86 +  {
   54.87 +    switch(state)
   54.88 +    {
   54.89 +      case WaitForLineOne:
   54.90 +      {
   54.91 +        if(line.equalsIgnoreCase("POST"))
   54.92 +        {
   54.93 +          printStatus(340, "send article to be posted. End with <CR-LF>.<CR-LF>");
   54.94 +          state = PostState.ReadingHeaders;
   54.95 +        }
   54.96 +        else
   54.97 +        {
   54.98 +          printStatus(500, "invalid command usage");
   54.99 +        }
  54.100 +        break;
  54.101 +      }
  54.102 +      case ReadingHeaders:
  54.103 +      {
  54.104 +        strHead.append(line);
  54.105 +        strHead.append(NNTPConnection.NEWLINE);
  54.106 +        
  54.107 +        if("".equals(line) || ".".equals(line))
  54.108 +        {
  54.109 +          // we finally met the blank line
  54.110 +          // separating headers from body
  54.111 +          
  54.112 +          try
  54.113 +          {
  54.114 +            // Parse the header using the InternetHeader class from JavaMail API
  54.115 +            headers = new InternetHeaders(
  54.116 +              new ByteArrayInputStream(strHead.toString().trim()
  54.117 +                .getBytes(connection.getCurrentCharset())));
  54.118 +
  54.119 +            // add the header entries for the article
  54.120 +            article.setHeaders(headers);
  54.121 +          }
  54.122 +          catch (MessagingException e)
  54.123 +          {
  54.124 +            e.printStackTrace();
  54.125 +            printStatus(500, "posting failed - invalid header");
  54.126 +            state = PostState.Finished;
  54.127 +            break;
  54.128 +          }
  54.129 +
  54.130 +          // Change charset for reading body; 
  54.131 +          // for multipart messages UTF-8 is returned
  54.132 +          connection.setCurrentCharset(article.getBodyCharset());
  54.133 +          
  54.134 +          state = PostState.ReadingBody;
  54.135 +          
  54.136 +          if(".".equals(line))
  54.137 +          {
  54.138 +            // Post an article without body
  54.139 +            postArticle(article);
  54.140 +            state = PostState.Finished;
  54.141 +          }
  54.142 +        }
  54.143 +        break;
  54.144 +      }
  54.145 +      case ReadingBody:
  54.146 +      {
  54.147 +        if(".".equals(line))
  54.148 +        {    
  54.149 +          // Set some headers needed for Over command
  54.150 +          headers.setHeader(Headers.LINES, Integer.toString(lineCount));
  54.151 +          headers.setHeader(Headers.BYTES, Long.toString(bodySize));
  54.152 +          
  54.153 +          if(strBody.length() >= 2)
  54.154 +          {
  54.155 +            strBody.deleteCharAt(strBody.length() - 1); // Remove last newline
  54.156 +            strBody.deleteCharAt(strBody.length() - 1); // Remove last CR
  54.157 +          }
  54.158 +          article.setBody(strBody.toString()); // set the article body
  54.159 +          
  54.160 +          postArticle(article);
  54.161 +          state = PostState.Finished;
  54.162 +        }
  54.163 +        else
  54.164 +        {
  54.165 +          bodySize += line.length() + 1;
  54.166 +          lineCount++;
  54.167 +          
  54.168 +          // Add line to body buffer
  54.169 +          strBody.append(line);
  54.170 +          strBody.append(NNTPConnection.NEWLINE);
  54.171 +          
  54.172 +          if(bodySize > maxBodySize)
  54.173 +          {
  54.174 +            printStatus(500, "article is too long");
  54.175 +            state = PostState.Finished;
  54.176 +            break;
  54.177 +          }
  54.178 +          
  54.179 +          // Check if this message is a MIME-multipart message and needs a
  54.180 +          // charset change
  54.181 +          try
  54.182 +          {
  54.183 +            line = line.toLowerCase(Locale.ENGLISH);
  54.184 +            if(line.startsWith(Headers.CONTENT_TYPE))
  54.185 +            {
  54.186 +              int idxStart = line.indexOf("charset=") + "charset=".length();
  54.187 +              int idxEnd   = line.indexOf(";", idxStart);
  54.188 +              if(idxEnd < 0)
  54.189 +              {
  54.190 +                idxEnd = line.length();
  54.191 +              }
  54.192 +
  54.193 +              if(idxStart > 0)
  54.194 +              {
  54.195 +                String charsetName = line.substring(idxStart, idxEnd);
  54.196 +                if(charsetName.length() > 0 && charsetName.charAt(0) == '"')
  54.197 +                {
  54.198 +                  charsetName = charsetName.substring(1, charsetName.length() - 1);
  54.199 +                }
  54.200 +
  54.201 +                try
  54.202 +                {
  54.203 +                  connection.setCurrentCharset(Charset.forName(charsetName));
  54.204 +                }
  54.205 +                catch(IllegalCharsetNameException ex)
  54.206 +                {
  54.207 +                  Log.msg("PostCommand: " + ex, false);
  54.208 +                }
  54.209 +                catch(UnsupportedCharsetException ex)
  54.210 +                {
  54.211 +                  Log.msg("PostCommand: " + ex, false);
  54.212 +                }
  54.213 +              } // if(idxStart > 0)
  54.214 +            }
  54.215 +          }
  54.216 +          catch(Exception ex)
  54.217 +          {
  54.218 +            ex.printStackTrace();
  54.219 +          }
  54.220 +        }
  54.221 +        break;
  54.222 +      }
  54.223 +      default:
  54.224 +        Log.msg("PostCommand::processLine(): already finished...", false);
  54.225 +    }
  54.226 +  }
  54.227 +  
  54.228 +  /**
  54.229 +   * Article is a control message and needs special handling.
  54.230 +   * @param article
  54.231 +   */
  54.232 +  private void controlMessage(Article article)
  54.233 +    throws IOException
  54.234 +  {
  54.235 +    String[] ctrl = article.getHeader(Headers.CONTROL)[0].split(" ");
  54.236 +    if(ctrl.length == 2) // "cancel <mid>"
  54.237 +    {
  54.238 +      try
  54.239 +      {
  54.240 +        Database.getInstance().delete(ctrl[1]);
  54.241 +        
  54.242 +        // Move cancel message to "control" group
  54.243 +        article.setHeader(Headers.NEWSGROUPS, "control");
  54.244 +        Database.getInstance().addArticle(article);
  54.245 +        printStatus(240, "article cancelled");
  54.246 +      }
  54.247 +      catch(SQLException ex)
  54.248 +      {
  54.249 +        Log.msg(ex, false);
  54.250 +        printStatus(500, "internal server error");
  54.251 +      }
  54.252 +    }
  54.253 +    else
  54.254 +    {
  54.255 +      printStatus(441, "unknown Control header");
  54.256 +    }
  54.257 +  }
  54.258 +  
  54.259 +  private void supersedeMessage(Article article)
  54.260 +    throws IOException
  54.261 +  {
  54.262 +    try
  54.263 +    {
  54.264 +      String oldMsg = article.getHeader(Headers.SUPERSEDES)[0];
  54.265 +      Database.getInstance().delete(oldMsg);
  54.266 +      Database.getInstance().addArticle(article);
  54.267 +      printStatus(240, "article replaced");
  54.268 +    }
  54.269 +    catch(SQLException ex)
  54.270 +    {
  54.271 +      Log.msg(ex, false);
  54.272 +      printStatus(500, "internal server error");
  54.273 +    }
  54.274 +  }
  54.275 +  
  54.276 +  private void postArticle(Article article) 
  54.277 +    throws IOException
  54.278 +  {
  54.279 +    if(article.getHeader(Headers.CONTROL)[0].length() > 0)
  54.280 +    {
  54.281 +      controlMessage(article);
  54.282 +    }
  54.283 +    else if(article.getHeader(Headers.SUPERSEDES)[0].length() > 0)
  54.284 +    {
  54.285 +      supersedeMessage(article);
  54.286 +    }
  54.287 +    else // Post the article regularily
  54.288 +    {
  54.289 +      // Try to create the article in the database or post it to
  54.290 +      // appropriate mailing list
  54.291 +      try
  54.292 +      {
  54.293 +        boolean success = false;
  54.294 +        String[] groupnames = article.getHeader(Headers.NEWSGROUPS)[0].split(",");
  54.295 +        for(String groupname : groupnames)
  54.296 +        {
  54.297 +          Group group = Database.getInstance().getGroup(groupname);
  54.298 +          if(group != null)
  54.299 +          {
  54.300 +            if(group.isMailingList() && !connection.isLocalConnection())
  54.301 +            {
  54.302 +              // Send to mailing list; the Dispatcher writes 
  54.303 +              // statistics to database
  54.304 +              Dispatcher.toList(article);
  54.305 +              success = true;
  54.306 +            }
  54.307 +            else
  54.308 +            {
  54.309 +              // Store in database
  54.310 +              if(!Database.getInstance().isArticleExisting(article.getMessageID()))
  54.311 +              {
  54.312 +                Database.getInstance().addArticle(article);
  54.313 +
  54.314 +                // Log this posting to statistics
  54.315 +                Stats.getInstance().mailPosted(
  54.316 +                  article.getHeader(Headers.NEWSGROUPS)[0]);
  54.317 +              }
  54.318 +              success = true;
  54.319 +            }
  54.320 +          }
  54.321 +        } // end for
  54.322 +
  54.323 +        if(success)
  54.324 +        {
  54.325 +          printStatus(240, "article posted ok");
  54.326 +          FeedManager.queueForPush(article);
  54.327 +        }
  54.328 +        else
  54.329 +        {
  54.330 +          printStatus(441, "newsgroup not found");
  54.331 +        }
  54.332 +      }
  54.333 +      catch(AddressException ex)
  54.334 +      {
  54.335 +        Log.msg(ex.getMessage(), true);
  54.336 +        printStatus(441, "invalid sender address");
  54.337 +      }
  54.338 +      catch(MessagingException ex)
  54.339 +      {
  54.340 +        // A MessageException is thrown when the sender email address is
  54.341 +        // invalid or something is wrong with the SMTP server.
  54.342 +        System.err.println(ex.getLocalizedMessage());
  54.343 +        printStatus(441, ex.getClass().getCanonicalName() + ": " + ex.getLocalizedMessage());
  54.344 +      }
  54.345 +      catch(SQLException ex)
  54.346 +      {
  54.347 +        ex.printStackTrace();
  54.348 +        printStatus(500, "internal server error");
  54.349 +      }
  54.350 +    }
  54.351 +  }
  54.352 +
  54.353 +}
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/org/sonews/daemon/command/PostState.java	Fri Jun 26 16:48:50 2009 +0200
    55.3 @@ -0,0 +1,29 @@
    55.4 +/*
    55.5 + *   SONEWS News Server
    55.6 + *   see AUTHORS for the list of contributors
    55.7 + *
    55.8 + *   This program is free software: you can redistribute it and/or modify
    55.9 + *   it under the terms of the GNU General Public License as published by
   55.10 + *   the Free Software Foundation, either version 3 of the License, or
   55.11 + *   (at your option) any later version.
   55.12 + *
   55.13 + *   This program is distributed in the hope that it will be useful,
   55.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   55.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   55.16 + *   GNU General Public License for more details.
   55.17 + *
   55.18 + *   You should have received a copy of the GNU General Public License
   55.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   55.20 + */
   55.21 +
   55.22 +package org.sonews.daemon.command;
   55.23 +
   55.24 +/**
   55.25 + * States of the POST command's finite state machine.
   55.26 + * @author Christian Lins
   55.27 + * @since sonews/0.5.0
   55.28 + */
   55.29 +enum PostState
   55.30 +{
   55.31 +  WaitForLineOne, ReadingHeaders, ReadingBody, Finished
   55.32 +}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/org/sonews/daemon/command/QuitCommand.java	Fri Jun 26 16:48:50 2009 +0200
    56.3 @@ -0,0 +1,54 @@
    56.4 +/*
    56.5 + *   SONEWS News Server
    56.6 + *   see AUTHORS for the list of contributors
    56.7 + *
    56.8 + *   This program is free software: you can redistribute it and/or modify
    56.9 + *   it under the terms of the GNU General Public License as published by
   56.10 + *   the Free Software Foundation, either version 3 of the License, or
   56.11 + *   (at your option) any later version.
   56.12 + *
   56.13 + *   This program is distributed in the hope that it will be useful,
   56.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   56.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   56.16 + *   GNU General Public License for more details.
   56.17 + *
   56.18 + *   You should have received a copy of the GNU General Public License
   56.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   56.20 + */
   56.21 +
   56.22 +package org.sonews.daemon.command;
   56.23 +
   56.24 +import java.io.IOException;
   56.25 +import java.sql.SQLException;
   56.26 +import org.sonews.daemon.NNTPConnection;
   56.27 +
   56.28 +/**
   56.29 + * Implementation of the QUIT command; client wants to shutdown the connection.
   56.30 + * @author Christian Lins
   56.31 + * @since sonews/0.5.0
   56.32 + */
   56.33 +public class QuitCommand extends AbstractCommand
   56.34 +{
   56.35 +
   56.36 +  public QuitCommand(final NNTPConnection conn)
   56.37 +  {
   56.38 +    super(conn);
   56.39 +  }
   56.40 +  
   56.41 +  @Override
   56.42 +  public boolean hasFinished()
   56.43 +  {
   56.44 +    return true;
   56.45 +  }
   56.46 +
   56.47 +  @Override
   56.48 +  public void processLine(final String line) 
   56.49 +    throws IOException, SQLException
   56.50 +  {    
   56.51 +    printStatus(205, "cya");
   56.52 +    
   56.53 +    this.connection.shutdownInput();
   56.54 +    this.connection.shutdownOutput();
   56.55 +  }
   56.56 +
   56.57 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/org/sonews/daemon/command/StatCommand.java	Fri Jun 26 16:48:50 2009 +0200
    57.3 @@ -0,0 +1,100 @@
    57.4 +/*
    57.5 + *   SONEWS News Server
    57.6 + *   see AUTHORS for the list of contributors
    57.7 + *
    57.8 + *   This program is free software: you can redistribute it and/or modify
    57.9 + *   it under the terms of the GNU General Public License as published by
   57.10 + *   the Free Software Foundation, either version 3 of the License, or
   57.11 + *   (at your option) any later version.
   57.12 + *
   57.13 + *   This program is distributed in the hope that it will be useful,
   57.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   57.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   57.16 + *   GNU General Public License for more details.
   57.17 + *
   57.18 + *   You should have received a copy of the GNU General Public License
   57.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   57.20 + */
   57.21 +
   57.22 +package org.sonews.daemon.command;
   57.23 +
   57.24 +import java.io.IOException;
   57.25 +import java.sql.SQLException;
   57.26 +import org.sonews.daemon.storage.Article;
   57.27 +import org.sonews.daemon.NNTPConnection;
   57.28 +
   57.29 +/**
   57.30 + * Implementation of the STAT command.
   57.31 + * @author Christian Lins
   57.32 + * @since sonews/0.5.0
   57.33 + */
   57.34 +public class StatCommand extends AbstractCommand
   57.35 +{
   57.36 +
   57.37 +  public StatCommand(final NNTPConnection conn)
   57.38 +  {
   57.39 +    super(conn);
   57.40 +  }
   57.41 +
   57.42 +  @Override
   57.43 +  public boolean hasFinished()
   57.44 +  {
   57.45 +    return true;
   57.46 +  }
   57.47 +
   57.48 +  // TODO: Method has various exit points => Refactor!
   57.49 +  @Override
   57.50 +  public void processLine(final String line)
   57.51 +    throws IOException, SQLException
   57.52 +  {
   57.53 +    final String[] command = line.split(" ");
   57.54 +
   57.55 +    Article article = null;
   57.56 +    if(command.length == 1)
   57.57 +    {
   57.58 +      article = getCurrentArticle();
   57.59 +      if(article == null)
   57.60 +      {
   57.61 +        printStatus(420, "no current article has been selected");
   57.62 +        return;
   57.63 +      }
   57.64 +    }
   57.65 +    else if(command[1].matches(NNTPConnection.MESSAGE_ID_PATTERN))
   57.66 +    {
   57.67 +      // Message-ID
   57.68 +      article = Article.getByMessageID(command[1]);
   57.69 +      if (article == null)
   57.70 +      {
   57.71 +        printStatus(430, "no such article found");
   57.72 +        return;
   57.73 +      }
   57.74 +    }
   57.75 +    else
   57.76 +    {
   57.77 +      // Message Number
   57.78 +      try
   57.79 +      {
   57.80 +        long aid = Long.parseLong(command[1]);
   57.81 +        article = Article.getByArticleNumber(aid, getCurrentGroup());
   57.82 +      }
   57.83 +      catch(NumberFormatException ex)
   57.84 +      {
   57.85 +        ex.printStackTrace();
   57.86 +      }
   57.87 +      catch(SQLException ex)
   57.88 +      {
   57.89 +        ex.printStackTrace();
   57.90 +      }
   57.91 +      if (article == null)
   57.92 +      {
   57.93 +        printStatus(423, "no such article number in this group");
   57.94 +        return;
   57.95 +      }
   57.96 +      setCurrentArticle(article);
   57.97 +    }
   57.98 +    
   57.99 +    printStatus(223, article.getIndexInGroup(getCurrentGroup()) + " " + article.getMessageID()
  57.100 +          + " article retrieved - request text separately");
  57.101 +  }
  57.102 +  
  57.103 +}
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/org/sonews/daemon/command/UnsupportedCommand.java	Fri Jun 26 16:48:50 2009 +0200
    58.3 @@ -0,0 +1,51 @@
    58.4 +/*
    58.5 + *   SONEWS News Server
    58.6 + *   see AUTHORS for the list of contributors
    58.7 + *
    58.8 + *   This program is free software: you can redistribute it and/or modify
    58.9 + *   it under the terms of the GNU General Public License as published by
   58.10 + *   the Free Software Foundation, either version 3 of the License, or
   58.11 + *   (at your option) any later version.
   58.12 + *
   58.13 + *   This program is distributed in the hope that it will be useful,
   58.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   58.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   58.16 + *   GNU General Public License for more details.
   58.17 + *
   58.18 + *   You should have received a copy of the GNU General Public License
   58.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   58.20 + */
   58.21 +
   58.22 +package org.sonews.daemon.command;
   58.23 +
   58.24 +import java.io.IOException;
   58.25 +import org.sonews.daemon.NNTPConnection;
   58.26 +
   58.27 +/**
   58.28 + * A default "Unsupported Command". Simply returns error code 500 and a
   58.29 + * "command not supported" message.
   58.30 + * @author Christian Lins
   58.31 + * @since sonews/0.5.0
   58.32 + */
   58.33 +public class UnsupportedCommand extends AbstractCommand
   58.34 +{
   58.35 +
   58.36 +  public UnsupportedCommand(final NNTPConnection conn)
   58.37 +  {
   58.38 +    super(conn);
   58.39 +  }
   58.40 +  
   58.41 +  @Override
   58.42 +  public boolean hasFinished()
   58.43 +  {
   58.44 +    return true;
   58.45 +  }
   58.46 +
   58.47 +  @Override
   58.48 +  public void processLine(final String line)
   58.49 +    throws IOException
   58.50 +  {
   58.51 +    printStatus(500, "command not supported");
   58.52 +  }
   58.53 +  
   58.54 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/org/sonews/daemon/command/XDaemonCommand.java	Fri Jun 26 16:48:50 2009 +0200
    59.3 @@ -0,0 +1,237 @@
    59.4 +/*
    59.5 + *   SONEWS News Server
    59.6 + *   see AUTHORS for the list of contributors
    59.7 + *
    59.8 + *   This program is free software: you can redistribute it and/or modify
    59.9 + *   it under the terms of the GNU General Public License as published by
   59.10 + *   the Free Software Foundation, either version 3 of the License, or
   59.11 + *   (at your option) any later version.
   59.12 + *
   59.13 + *   This program is distributed in the hope that it will be useful,
   59.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   59.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   59.16 + *   GNU General Public License for more details.
   59.17 + *
   59.18 + *   You should have received a copy of the GNU General Public License
   59.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   59.20 + */
   59.21 +
   59.22 +package org.sonews.daemon.command;
   59.23 +
   59.24 +import java.io.IOException;
   59.25 +import java.net.InetSocketAddress;
   59.26 +import java.sql.SQLException;
   59.27 +import java.util.List;
   59.28 +import org.sonews.daemon.BootstrapConfig;
   59.29 +import org.sonews.daemon.Config;
   59.30 +import org.sonews.daemon.NNTPConnection;
   59.31 +import org.sonews.daemon.storage.Database;
   59.32 +import org.sonews.daemon.storage.Group;
   59.33 +import org.sonews.feed.FeedManager;
   59.34 +import org.sonews.feed.Subscription;
   59.35 +import org.sonews.util.Stats;
   59.36 +
   59.37 +/**
   59.38 + * The XDAEMON command allows a client to get/set properties of the
   59.39 + * running server daemon. Only locally connected clients are allowed to
   59.40 + * use this command.
   59.41 + * The restriction to localhost connection can be suppressed by overriding
   59.42 + * the sonews.xdaemon.host bootstrap config property.
   59.43 + * @author Christian Lins
   59.44 + * @since sonews/0.5.0
   59.45 + */
   59.46 +public class XDaemonCommand extends AbstractCommand
   59.47 +{
   59.48 +  
   59.49 +  public XDaemonCommand(NNTPConnection conn)
   59.50 +  {
   59.51 +    super(conn);
   59.52 +  }
   59.53 +
   59.54 +  @Override
   59.55 +  public boolean hasFinished()
   59.56 +  {
   59.57 +    return true;
   59.58 +  }
   59.59 +
   59.60 +  // TODO: Refactor this method to reduce complexity!
   59.61 +  @Override
   59.62 +  public void processLine(String line) throws IOException, SQLException
   59.63 +  {
   59.64 +    InetSocketAddress addr = (InetSocketAddress)connection.getChannel().socket()
   59.65 +      .getRemoteSocketAddress();
   59.66 +    if(addr.getHostName().equals(
   59.67 +      BootstrapConfig.getInstance().get(BootstrapConfig.XDAEMON_HOST, "localhost")))
   59.68 +    {
   59.69 +      String[] commands = line.split(" ", 4);
   59.70 +      if(commands.length == 3 && commands[1].equalsIgnoreCase("LIST"))
   59.71 +      {
   59.72 +        if(commands[2].equalsIgnoreCase("CONFIGKEYS"))
   59.73 +        {
   59.74 +          printStatus(200, "list of available config keys follows");
   59.75 +          for(String key : Config.AVAILABLE_KEYS)
   59.76 +          {
   59.77 +            println(key);
   59.78 +          }
   59.79 +          println(".");
   59.80 +        }
   59.81 +        else if(commands[2].equalsIgnoreCase("PEERINGRULES"))
   59.82 +        {
   59.83 +          List<Subscription> pull = 
   59.84 +            Database.getInstance().getSubscriptions(FeedManager.TYPE_PULL);
   59.85 +          List<Subscription> push =
   59.86 +            Database.getInstance().getSubscriptions(FeedManager.TYPE_PUSH);
   59.87 +          printStatus(200,"list of peering rules follows");
   59.88 +          for(Subscription sub : pull)
   59.89 +          {
   59.90 +            println("PULL " + sub.getHost() + ":" + sub.getPort() 
   59.91 +              + " " + sub.getGroup());
   59.92 +          }
   59.93 +          for(Subscription sub : push)
   59.94 +          {
   59.95 +            println("PUSH " + sub.getHost() + ":" + sub.getPort() 
   59.96 +              + " " + sub.getGroup());
   59.97 +          }
   59.98 +          println(".");
   59.99 +        }
  59.100 +        else
  59.101 +        {
  59.102 +          printStatus(501, "unknown sub command");
  59.103 +        }
  59.104 +      }
  59.105 +      else if(commands.length == 3 && commands[1].equalsIgnoreCase("DELETE"))
  59.106 +      {
  59.107 +        Database.getInstance().delete(commands[2]);
  59.108 +        printStatus(200, "article " + commands[2] + " deleted");
  59.109 +      }
  59.110 +      else if(commands.length == 4 && commands[1].equalsIgnoreCase("GROUPADD"))
  59.111 +      {
  59.112 +        Database.getInstance().addGroup(commands[2], Integer.parseInt(commands[3]));
  59.113 +        printStatus(200, "group " + commands[2] + " created");
  59.114 +      }
  59.115 +      else if(commands.length == 3 && commands[1].equalsIgnoreCase("GROUPDEL"))
  59.116 +      {
  59.117 +        Group group = Database.getInstance().getGroup(commands[2]);
  59.118 +        if(group == null)
  59.119 +        {
  59.120 +          printStatus(400, "group not found");
  59.121 +        }
  59.122 +        else
  59.123 +        {
  59.124 +          group.setFlag(Group.DELETED);
  59.125 +          printStatus(200, "group " + commands[2] + " marked as deleted");
  59.126 +        }
  59.127 +      }
  59.128 +      else if(commands.length == 4 && commands[1].equalsIgnoreCase("SET"))
  59.129 +      {
  59.130 +        String key = commands[2];
  59.131 +        String val = commands[3];
  59.132 +        Config.getInstance().set(key, val);
  59.133 +        printStatus(200, "new config value set");
  59.134 +      }
  59.135 +      else if(commands.length == 3 && commands[1].equalsIgnoreCase("GET"))
  59.136 +      {
  59.137 +        String key = commands[2];
  59.138 +        String val = Config.getInstance().get(key, null);
  59.139 +        if(val != null)
  59.140 +        {
  59.141 +          printStatus(200, "config value for " + key + " follows");
  59.142 +          println(val);
  59.143 +          println(".");
  59.144 +        }
  59.145 +        else
  59.146 +        {
  59.147 +          printStatus(400, "config value not set");
  59.148 +        }
  59.149 +      }
  59.150 +      else if(commands.length >= 3 && commands[1].equalsIgnoreCase("LOG"))
  59.151 +      {
  59.152 +        Group group = null;
  59.153 +        if(commands.length > 3)
  59.154 +        {
  59.155 +          group = Group.getByName(commands[3]);
  59.156 +        }
  59.157 +
  59.158 +        if(commands[2].equalsIgnoreCase("CONNECTED_CLIENTS"))
  59.159 +        {
  59.160 +          printStatus(200, "number of connections follow");
  59.161 +          println(Integer.toString(Stats.getInstance().connectedClients()));
  59.162 +          println(".");
  59.163 +        }
  59.164 +        else if(commands[2].equalsIgnoreCase("POSTED_NEWS"))
  59.165 +        {
  59.166 +          printStatus(200, "hourly numbers of posted news yesterday");
  59.167 +          for(int n = 0; n < 24; n++)
  59.168 +          {
  59.169 +            println(n + " " + Stats.getInstance()
  59.170 +              .getYesterdaysEvents(Stats.POSTED_NEWS, n, group));
  59.171 +          }
  59.172 +          println(".");
  59.173 +        }
  59.174 +        else if(commands[2].equalsIgnoreCase("GATEWAYED_NEWS"))
  59.175 +        {
  59.176 +          printStatus(200, "hourly numbers of gatewayed news yesterday");
  59.177 +          for(int n = 0; n < 24; n++)
  59.178 +          {
  59.179 +            println(n + " " + Stats.getInstance()
  59.180 +              .getYesterdaysEvents(Stats.GATEWAYED_NEWS, n, group));
  59.181 +          }
  59.182 +          println(".");
  59.183 +        }
  59.184 +        else if(commands[2].equalsIgnoreCase("TRANSMITTED_NEWS"))
  59.185 +        {
  59.186 +          printStatus(200, "hourly numbers of news transmitted to peers yesterday");
  59.187 +          for(int n = 0; n < 24; n++)
  59.188 +          {
  59.189 +            println(n + " " + Stats.getInstance()
  59.190 +              .getYesterdaysEvents(Stats.FEEDED_NEWS, n, group));
  59.191 +          }
  59.192 +          println(".");
  59.193 +        }
  59.194 +        else if(commands[2].equalsIgnoreCase("HOSTED_NEWS"))
  59.195 +        {
  59.196 +          printStatus(200, "number of overall hosted news");
  59.197 +          println(Integer.toString(Stats.getInstance().getNumberOfNews()));
  59.198 +          println(".");
  59.199 +        }
  59.200 +        else if(commands[2].equalsIgnoreCase("HOSTED_GROUPS"))
  59.201 +        {
  59.202 +          printStatus(200, "number of hosted groups");
  59.203 +          println(Integer.toString(Stats.getInstance().getNumberOfGroups()));
  59.204 +          println(".");
  59.205 +        }
  59.206 +        else if(commands[2].equalsIgnoreCase("POSTED_NEWS_PER_HOUR"))
  59.207 +        {
  59.208 +          printStatus(200, "posted news per hour");
  59.209 +          println(Double.toString(Stats.getInstance().postedPerHour(-1)));
  59.210 +          println(".");
  59.211 +        }
  59.212 +        else if(commands[2].equalsIgnoreCase("FEEDED_NEWS_PER_HOUR"))
  59.213 +        {
  59.214 +          printStatus(200, "feeded news per hour");
  59.215 +          println(Double.toString(Stats.getInstance().feededPerHour(-1)));
  59.216 +          println(".");
  59.217 +        }
  59.218 +        else if(commands[2].equalsIgnoreCase("GATEWAYED_NEWS_PER_HOUR"))
  59.219 +        {
  59.220 +          printStatus(200, "gatewayed news per hour");
  59.221 +          println(Double.toString(Stats.getInstance().gatewayedPerHour(-1)));
  59.222 +          println(".");
  59.223 +        }
  59.224 +        else
  59.225 +        {
  59.226 +          printStatus(501, "unknown sub command");
  59.227 +        }
  59.228 +      }
  59.229 +      else
  59.230 +      {
  59.231 +        printStatus(500, "invalid command usage");
  59.232 +      }
  59.233 +    }
  59.234 +    else
  59.235 +    {
  59.236 +      printStatus(500, "not allowed");
  59.237 +    }
  59.238 +  }
  59.239 +  
  59.240 +}
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/org/sonews/daemon/command/XPatCommand.java	Fri Jun 26 16:48:50 2009 +0200
    60.3 @@ -0,0 +1,89 @@
    60.4 +/*
    60.5 + *   SONEWS News Server
    60.6 + *   see AUTHORS for the list of contributors
    60.7 + *
    60.8 + *   This program is free software: you can redistribute it and/or modify
    60.9 + *   it under the terms of the GNU General Public License as published by
   60.10 + *   the Free Software Foundation, either version 3 of the License, or
   60.11 + *   (at your option) any later version.
   60.12 + *
   60.13 + *   This program is distributed in the hope that it will be useful,
   60.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   60.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   60.16 + *   GNU General Public License for more details.
   60.17 + *
   60.18 + *   You should have received a copy of the GNU General Public License
   60.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   60.20 + */
   60.21 +
   60.22 +package org.sonews.daemon.command;
   60.23 +
   60.24 +import java.io.IOException;
   60.25 +import java.sql.SQLException;
   60.26 +import org.sonews.daemon.NNTPConnection;
   60.27 +
   60.28 +/**
   60.29 + * <pre>
   60.30 + *   XPAT header range|<message-id> pat [pat...]
   60.31 + *
   60.32 + *   The XPAT command is used to retrieve specific headers from
   60.33 + *   specific articles, based on pattern matching on the contents of
   60.34 + *   the header. This command was first available in INN.
   60.35 + *
   60.36 + *   The required header parameter is the name of a header line (e.g.
   60.37 + *   "subject") in a news group article. See RFC-1036 for a list
   60.38 + *   of valid header lines. The required range argument may be
   60.39 + *   any of the following:
   60.40 + *               an article number
   60.41 + *               an article number followed by a dash to indicate
   60.42 + *                  all following
   60.43 + *               an article number followed by a dash followed by
   60.44 + *                  another article number
   60.45 + *
   60.46 + *   The required message-id argument indicates a specific
   60.47 + *   article. The range and message-id arguments are mutually
   60.48 + *   exclusive. At least one pattern in wildmat must be specified
   60.49 + *   as well. If there are additional arguments the are joined
   60.50 + *   together separated by a single space to form one complete
   60.51 + *   pattern. Successful responses start with a 221 response
   60.52 + *   followed by a the headers from all messages in which the
   60.53 + *   pattern matched the contents of the specified header line. This
   60.54 + *   includes an empty list. Once the output is complete, a period
   60.55 + *   is sent on a line by itself. If the optional argument is a
   60.56 + *   message-id and no such article exists, the 430 error response
   60.57 + *   is returned. A 502 response will be returned if the client only
   60.58 + *   has permission to transfer articles.
   60.59 + *
   60.60 + *   Responses
   60.61 + *
   60.62 + *       221 Header follows
   60.63 + *       430 no such article
   60.64 + *       502 no permission
   60.65 + * </pre>
   60.66 + * [Source:"draft-ietf-nntp-imp-02.txt"] [Copyright: 1998 S. Barber]
   60.67 + * 
   60.68 + * @author Christian Lins
   60.69 + * @since sonews/0.5.0
   60.70 + */
   60.71 +public class XPatCommand extends AbstractCommand
   60.72 +{
   60.73 +
   60.74 +  public XPatCommand(final NNTPConnection conn)
   60.75 +  {
   60.76 +    super(conn);
   60.77 +  }
   60.78 +  
   60.79 +  @Override
   60.80 +  public boolean hasFinished()
   60.81 +  {
   60.82 +    return true;
   60.83 +  }
   60.84 +
   60.85 +  @Override
   60.86 +  public void processLine(final String line) 
   60.87 +    throws IOException, SQLException
   60.88 +  {
   60.89 +    printStatus(500, "not (yet) supported");
   60.90 +  }
   60.91 +
   60.92 +}
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/org/sonews/daemon/command/package.html	Fri Jun 26 16:48:50 2009 +0200
    61.3 @@ -0,0 +1,1 @@
    61.4 +Contains a class for every NNTP command.
    61.5 \ No newline at end of file
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/org/sonews/daemon/package.html	Fri Jun 26 16:48:50 2009 +0200
    62.3 @@ -0,0 +1,1 @@
    62.4 +Contains basic classes of the daemon.
    62.5 \ No newline at end of file
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/org/sonews/daemon/storage/Article.java	Fri Jun 26 16:48:50 2009 +0200
    63.3 @@ -0,0 +1,401 @@
    63.4 +/*
    63.5 + *   SONEWS News Server
    63.6 + *   see AUTHORS for the list of contributors
    63.7 + *
    63.8 + *   This program is free software: you can redistribute it and/or modify
    63.9 + *   it under the terms of the GNU General Public License as published by
   63.10 + *   the Free Software Foundation, either version 3 of the License, or
   63.11 + *   (at your option) any later version.
   63.12 + *
   63.13 + *   This program is distributed in the hope that it will be useful,
   63.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   63.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   63.16 + *   GNU General Public License for more details.
   63.17 + *
   63.18 + *   You should have received a copy of the GNU General Public License
   63.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   63.20 + */
   63.21 +
   63.22 +package org.sonews.daemon.storage;
   63.23 +
   63.24 +import org.sonews.daemon.Config;
   63.25 +import java.io.BufferedReader;
   63.26 +import java.io.ByteArrayInputStream;
   63.27 +import java.io.IOException;
   63.28 +import java.io.InputStream;
   63.29 +import java.io.InputStreamReader;
   63.30 +import java.nio.charset.Charset;
   63.31 +import java.sql.SQLException;
   63.32 +import java.util.UUID;
   63.33 +import java.util.ArrayList;
   63.34 +import java.util.Enumeration;
   63.35 +import java.util.List;
   63.36 +import javax.mail.Header;
   63.37 +import javax.mail.Message;
   63.38 +import javax.mail.MessagingException;
   63.39 +import javax.mail.Multipart;
   63.40 +import javax.mail.internet.InternetHeaders;
   63.41 +import javax.mail.internet.MimeUtility;
   63.42 +import org.sonews.util.Log;
   63.43 +
   63.44 +/**
   63.45 + * Represents a newsgroup article.
   63.46 + * @author Christian Lins
   63.47 + * @author Denis Schwerdel
   63.48 + * @since n3tpd/0.1
   63.49 + */
   63.50 +public class Article extends ArticleHead
   63.51 +{
   63.52 +  
   63.53 +  /**
   63.54 +   * Loads the Article identified by the given ID from the Database.
   63.55 +   * @param messageID
   63.56 +   * @return null if Article is not found or if an error occurred.
   63.57 +   */
   63.58 +  public static Article getByMessageID(final String messageID)
   63.59 +  {
   63.60 +    try
   63.61 +    {
   63.62 +      return Database.getInstance().getArticle(messageID);
   63.63 +    }
   63.64 +    catch(SQLException ex)
   63.65 +    {
   63.66 +      ex.printStackTrace();
   63.67 +      return null;
   63.68 +    }
   63.69 +  }
   63.70 +  
   63.71 +  public static Article getByArticleNumber(long articleIndex, Group group)
   63.72 +    throws SQLException
   63.73 +  {
   63.74 +    return Database.getInstance().getArticle(articleIndex, group.getID()); 
   63.75 +  }
   63.76 +  
   63.77 +  private String              body       = "";
   63.78 +  private String              headerSrc  = null;
   63.79 +  
   63.80 +  /**
   63.81 +   * Default constructor.
   63.82 +   */
   63.83 +  public Article()
   63.84 +  {
   63.85 +  }
   63.86 +  
   63.87 +  /**
   63.88 +   * Creates a new Article object using the date from the given
   63.89 +   * raw data.
   63.90 +   * This construction has only package visibility.
   63.91 +   */
   63.92 +  Article(String headers, String body)
   63.93 +  {
   63.94 +    try
   63.95 +    {
   63.96 +      this.body  = body;
   63.97 +
   63.98 +      // Parse the header
   63.99 +      this.headers = new InternetHeaders(
  63.100 +        new ByteArrayInputStream(headers.getBytes()));
  63.101 +      
  63.102 +      this.headerSrc = headers;
  63.103 +    }
  63.104 +    catch(MessagingException ex)
  63.105 +    {
  63.106 +      ex.printStackTrace();
  63.107 +    }
  63.108 +  }
  63.109 +
  63.110 +  /**
  63.111 +   * Creates an Article instance using the data from the javax.mail.Message
  63.112 +   * object.
  63.113 +   * @see javax.mail.Message
  63.114 +   * @param msg
  63.115 +   * @throws IOException
  63.116 +   * @throws MessagingException
  63.117 +   */
  63.118 +  public Article(final Message msg)
  63.119 +    throws IOException, MessagingException
  63.120 +  {
  63.121 +    this.headers = new InternetHeaders();
  63.122 +
  63.123 +    for(Enumeration e = msg.getAllHeaders() ; e.hasMoreElements();) 
  63.124 +    {
  63.125 +      final Header header = (Header)e.nextElement();
  63.126 +      this.headers.addHeader(header.getName(), header.getValue());
  63.127 +    }
  63.128 +    
  63.129 +    // The "content" of the message can be a String if it's a simple text/plain
  63.130 +    // message, a Multipart object or an InputStream if the content is unknown.
  63.131 +    final Object content = msg.getContent();
  63.132 +    if(content instanceof String)
  63.133 +    {
  63.134 +      this.body = (String)content;
  63.135 +    }
  63.136 +    else if(content instanceof Multipart) // probably subclass MimeMultipart
  63.137 +    {
  63.138 +      // We're are not interested in the different parts of the MultipartMessage,
  63.139 +      // so we simply read in all data which *can* be huge.
  63.140 +      InputStream in = msg.getInputStream();
  63.141 +      this.body = readContent(in);
  63.142 +    }
  63.143 +    else if(content instanceof InputStream)
  63.144 +    {
  63.145 +      // The message format is unknown to the Message class, but we can
  63.146 +      // simply read in the whole message data.
  63.147 +      this.body = readContent((InputStream)content);
  63.148 +    }
  63.149 +    else
  63.150 +    {
  63.151 +      // Unknown content is probably a malformed mail we should skip.
  63.152 +      // On the other hand we produce an inconsistent mail mirror, but no
  63.153 +      // mail system must transport invalid content.
  63.154 +      Log.msg("Skipping message due to unknown content. Throwing exception...", true);
  63.155 +      throw new MessagingException("Unknown content: " + content);
  63.156 +    }
  63.157 +    
  63.158 +    // Validate headers
  63.159 +    validateHeaders();
  63.160 +  }
  63.161 +
  63.162 +  /**
  63.163 +   * Reads lines from the given InputString into a String object.
  63.164 +   * TODO: Move this generalized method to org.sonews.util.io.Resource.
  63.165 +   * @param in
  63.166 +   * @return
  63.167 +   * @throws IOException
  63.168 +   */
  63.169 +  private String readContent(InputStream in)
  63.170 +    throws IOException
  63.171 +  {
  63.172 +    StringBuilder buf = new StringBuilder();
  63.173 +    
  63.174 +    BufferedReader rin = new BufferedReader(new InputStreamReader(in));
  63.175 +    String line =  rin.readLine();
  63.176 +    while(line != null)
  63.177 +    {
  63.178 +      buf.append('\n');
  63.179 +      buf.append(line);
  63.180 +      line = rin.readLine();
  63.181 +    }
  63.182 +    
  63.183 +    return buf.toString();
  63.184 +  }
  63.185 +
  63.186 +  /**
  63.187 +   * Removes the header identified by the given key.
  63.188 +   * @param headerKey
  63.189 +   */
  63.190 +  public void removeHeader(final String headerKey)
  63.191 +  {
  63.192 +    this.headers.removeHeader(headerKey);
  63.193 +    this.headerSrc = null;
  63.194 +  }
  63.195 +
  63.196 +  /**
  63.197 +   * Generates a message id for this article and sets it into
  63.198 +   * the header object. You have to update the Database manually to make this
  63.199 +   * change persistent.
  63.200 +   * Note: a Message-ID should never be changed and only generated once.
  63.201 +   */
  63.202 +  private String generateMessageID()
  63.203 +  {
  63.204 +    String msgID = "<" + UUID.randomUUID() + "@"
  63.205 +        + Config.getInstance().get(Config.HOSTNAME, "localhost") + ">";
  63.206 +    
  63.207 +    this.headers.setHeader(Headers.MESSAGE_ID, msgID);
  63.208 +    
  63.209 +    return msgID;
  63.210 +  }
  63.211 +
  63.212 +  /**
  63.213 +   * Returns the body string.
  63.214 +   */
  63.215 +  public String getBody()
  63.216 +  {
  63.217 +    return body;
  63.218 +  }
  63.219 +
  63.220 +  /**
  63.221 +   * @return Charset of the body text
  63.222 +   */
  63.223 +  public Charset getBodyCharset()
  63.224 +  {
  63.225 +    // We espect something like 
  63.226 +    // Content-Type: text/plain; charset=ISO-8859-15
  63.227 +    String contentType = getHeader(Headers.CONTENT_TYPE)[0];
  63.228 +    int idxCharsetStart = contentType.indexOf("charset=") + "charset=".length();
  63.229 +    int idxCharsetEnd   = contentType.indexOf(";", idxCharsetStart);
  63.230 +    
  63.231 +    String charsetName = "UTF-8";
  63.232 +    if(idxCharsetStart >= 0 && idxCharsetStart < contentType.length())
  63.233 +    {
  63.234 +      if(idxCharsetEnd < 0)
  63.235 +      {
  63.236 +        charsetName = contentType.substring(idxCharsetStart);
  63.237 +      }
  63.238 +      else
  63.239 +      {
  63.240 +        charsetName = contentType.substring(idxCharsetStart, idxCharsetEnd);
  63.241 +      }
  63.242 +    }
  63.243 +    
  63.244 +    // Sometimes there are '"' around the name
  63.245 +    if(charsetName.length() > 2 &&
  63.246 +      charsetName.charAt(0) == '"' && charsetName.endsWith("\""))
  63.247 +    {
  63.248 +      charsetName = charsetName.substring(1, charsetName.length() - 2);
  63.249 +    }
  63.250 +    
  63.251 +    // Create charset
  63.252 +    Charset charset = Charset.forName("UTF-8"); // This MUST be supported by JVM
  63.253 +    try
  63.254 +    {
  63.255 +      charset = Charset.forName(charsetName);
  63.256 +    }
  63.257 +    catch(Exception ex)
  63.258 +    {
  63.259 +      Log.msg(ex.getMessage(), false);
  63.260 +      Log.msg("Article.getBodyCharset(): Unknown charset: " + charsetName, false);
  63.261 +    }
  63.262 +    return charset;
  63.263 +  }
  63.264 +  
  63.265 +  /**
  63.266 +   * @return Numerical IDs of the newsgroups this Article belongs to.
  63.267 +   */
  63.268 +  List<Group> getGroups()
  63.269 +  {
  63.270 +    String[]         groupnames = getHeader(Headers.NEWSGROUPS)[0].split(",");
  63.271 +    ArrayList<Group> groups     = new ArrayList<Group>();
  63.272 +
  63.273 +    try
  63.274 +    {
  63.275 +      for(String newsgroup : groupnames)
  63.276 +      {
  63.277 +        newsgroup = newsgroup.trim();
  63.278 +        Group group = Database.getInstance().getGroup(newsgroup);
  63.279 +        if(group != null &&         // If the server does not provide the group, ignore it
  63.280 +          !groups.contains(group))  // Yes, there may be duplicates
  63.281 +        {
  63.282 +          groups.add(group);
  63.283 +        }
  63.284 +      }
  63.285 +    }
  63.286 +    catch (SQLException ex)
  63.287 +    {
  63.288 +      ex.printStackTrace();
  63.289 +      return null;
  63.290 +    }
  63.291 +    return groups;
  63.292 +  }
  63.293 +
  63.294 +  public void setBody(String body)
  63.295 +  {
  63.296 +    this.body = body;
  63.297 +  }
  63.298 +  
  63.299 +  /**
  63.300 +   * 
  63.301 +   * @param groupname Name(s) of newsgroups
  63.302 +   */
  63.303 +  public void setGroup(String groupname)
  63.304 +  {
  63.305 +    this.headers.setHeader(Headers.NEWSGROUPS, groupname);
  63.306 +  }
  63.307 +
  63.308 +  public String getMessageID()
  63.309 +  {
  63.310 +    String[] msgID = getHeader(Headers.MESSAGE_ID);
  63.311 +    return msgID[0];
  63.312 +  }
  63.313 +
  63.314 +  public Enumeration getAllHeaders()
  63.315 +  {
  63.316 +    return this.headers.getAllHeaders();
  63.317 +  }
  63.318 +  
  63.319 +  /**
  63.320 +   * @return Header source code of this Article.
  63.321 +   */
  63.322 +  public String getHeaderSource()
  63.323 +  {
  63.324 +    if(this.headerSrc != null)
  63.325 +    {
  63.326 +      return this.headerSrc;
  63.327 +    }
  63.328 +
  63.329 +    StringBuffer buf = new StringBuffer();
  63.330 +    
  63.331 +    for(Enumeration en = this.headers.getAllHeaders(); en.hasMoreElements();)
  63.332 +    {
  63.333 +      Header entry = (Header)en.nextElement();
  63.334 +
  63.335 +      buf.append(entry.getName());
  63.336 +      buf.append(": ");
  63.337 +      buf.append(
  63.338 +        MimeUtility.fold(entry.getName().length() + 2, entry.getValue()));
  63.339 +
  63.340 +      if(en.hasMoreElements())
  63.341 +      {
  63.342 +        buf.append("\r\n");
  63.343 +      }
  63.344 +    }
  63.345 +    
  63.346 +    this.headerSrc = buf.toString();
  63.347 +    return this.headerSrc;
  63.348 +  }
  63.349 +  
  63.350 +  public long getIndexInGroup(Group group)
  63.351 +    throws SQLException
  63.352 +  {
  63.353 +    return Database.getInstance().getArticleIndex(this, group);
  63.354 +  }
  63.355 +  
  63.356 +  /**
  63.357 +   * Sets the headers of this Article. If headers contain no
  63.358 +   * Message-Id a new one is created.
  63.359 +   * @param headers
  63.360 +   */
  63.361 +  public void setHeaders(InternetHeaders headers)
  63.362 +  {
  63.363 +    this.headers = headers;
  63.364 +    validateHeaders();
  63.365 +  }
  63.366 +  
  63.367 +  /**
  63.368 +   * @return String containing the Message-ID.
  63.369 +   */
  63.370 +  @Override
  63.371 +  public String toString()
  63.372 +  {
  63.373 +    return getMessageID();
  63.374 +  }
  63.375 +  
  63.376 +  /**
  63.377 +   * Checks some headers for their validity and generates an
  63.378 +   * appropriate Path-header for this host if not yet existing.
  63.379 +   * This method is called by some Article constructors and the
  63.380 +   * method setHeaders().
  63.381 +   * @return true if something on the headers was changed.
  63.382 +   */
  63.383 +  private void validateHeaders()
  63.384 +  {
  63.385 +    // Check for valid Path-header
  63.386 +    final String path = getHeader(Headers.PATH)[0];
  63.387 +    final String host = Config.getInstance().get(Config.HOSTNAME, "localhost");
  63.388 +    if(!path.startsWith(host))
  63.389 +    {
  63.390 +      StringBuffer pathBuf = new StringBuffer();
  63.391 +      pathBuf.append(host);
  63.392 +      pathBuf.append('!');
  63.393 +      pathBuf.append(path);
  63.394 +      this.headers.setHeader(Headers.PATH, pathBuf.toString());
  63.395 +    }
  63.396 +    
  63.397 +    // Generate a messageID if no one is existing
  63.398 +    if(getMessageID().equals(""))
  63.399 +    {
  63.400 +      generateMessageID();
  63.401 +    }
  63.402 +  }
  63.403 +
  63.404 +}
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/org/sonews/daemon/storage/ArticleHead.java	Fri Jun 26 16:48:50 2009 +0200
    64.3 @@ -0,0 +1,78 @@
    64.4 +/*
    64.5 + *   SONEWS News Server
    64.6 + *   see AUTHORS for the list of contributors
    64.7 + *
    64.8 + *   This program is free software: you can redistribute it and/or modify
    64.9 + *   it under the terms of the GNU General Public License as published by
   64.10 + *   the Free Software Foundation, either version 3 of the License, or
   64.11 + *   (at your option) any later version.
   64.12 + *
   64.13 + *   This program is distributed in the hope that it will be useful,
   64.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   64.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   64.16 + *   GNU General Public License for more details.
   64.17 + *
   64.18 + *   You should have received a copy of the GNU General Public License
   64.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   64.20 + */
   64.21 +
   64.22 +package org.sonews.daemon.storage;
   64.23 +
   64.24 +import java.io.ByteArrayInputStream;
   64.25 +import javax.mail.MessagingException;
   64.26 +import javax.mail.internet.InternetHeaders;
   64.27 +
   64.28 +/**
   64.29 + * An article with no body only headers.
   64.30 + * @author Christian Lins
   64.31 + * @since sonews/0.5.0
   64.32 + */
   64.33 +public class ArticleHead 
   64.34 +{
   64.35 +
   64.36 +  protected InternetHeaders headers;
   64.37 +  
   64.38 +  protected ArticleHead()
   64.39 +  {
   64.40 +  }
   64.41 +  
   64.42 +  public ArticleHead(String headers)
   64.43 +  {
   64.44 +    try
   64.45 +    {
   64.46 +      // Parse the header
   64.47 +      this.headers = new InternetHeaders(
   64.48 +          new ByteArrayInputStream(headers.getBytes()));
   64.49 +    }
   64.50 +    catch(MessagingException ex)
   64.51 +    {
   64.52 +      ex.printStackTrace();
   64.53 +    }
   64.54 +  }
   64.55 +  
   64.56 +  /**
   64.57 +   * Returns the header field with given name.
   64.58 +   * @param name
   64.59 +   * @return Header values or empty string.
   64.60 +   */
   64.61 +  public String[] getHeader(String name)
   64.62 +  {
   64.63 +    String[] ret = this.headers.getHeader(name);
   64.64 +    if(ret == null)
   64.65 +    {
   64.66 +      ret = new String[]{""};
   64.67 +    }
   64.68 +    return ret;
   64.69 +  }
   64.70 +  
   64.71 +  /**
   64.72 +   * Sets the header value identified through the header name.
   64.73 +   * @param name
   64.74 +   * @param value
   64.75 +   */
   64.76 +  public void setHeader(String name, String value)
   64.77 +  {
   64.78 +    this.headers.setHeader(name, value);
   64.79 +  }
   64.80 +  
   64.81 +}
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/org/sonews/daemon/storage/Database.java	Fri Jun 26 16:48:50 2009 +0200
    65.3 @@ -0,0 +1,1353 @@
    65.4 +/*
    65.5 + *   SONEWS News Server
    65.6 + *   see AUTHORS for the list of contributors
    65.7 + *
    65.8 + *   This program is free software: you can redistribute it and/or modify
    65.9 + *   it under the terms of the GNU General Public License as published by
   65.10 + *   the Free Software Foundation, either version 3 of the License, or
   65.11 + *   (at your option) any later version.
   65.12 + *
   65.13 + *   This program is distributed in the hope that it will be useful,
   65.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   65.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   65.16 + *   GNU General Public License for more details.
   65.17 + *
   65.18 + *   You should have received a copy of the GNU General Public License
   65.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   65.20 + */
   65.21 +
   65.22 +package org.sonews.daemon.storage;
   65.23 +
   65.24 +import java.sql.Connection;
   65.25 +import java.sql.DriverManager;
   65.26 +import java.sql.ResultSet;
   65.27 +import java.sql.SQLException;
   65.28 +import java.sql.Statement;
   65.29 +import java.sql.PreparedStatement;
   65.30 +import java.util.ArrayList;
   65.31 +import java.util.Enumeration;
   65.32 +import java.util.List;
   65.33 +import java.util.Map;
   65.34 +import java.util.concurrent.ConcurrentHashMap;
   65.35 +import javax.mail.Header;
   65.36 +import javax.mail.internet.InternetAddress;
   65.37 +import javax.mail.internet.MimeUtility;
   65.38 +import org.sonews.daemon.BootstrapConfig;
   65.39 +import org.sonews.util.Log;
   65.40 +import org.sonews.feed.Subscription;
   65.41 +import org.sonews.util.Pair;
   65.42 +
   65.43 +/**
   65.44 + * Database facade class.
   65.45 + * @author Christian Lins
   65.46 + * @since sonews/0.5.0
   65.47 + */
   65.48 +// TODO: Refactor this class to reduce size (e.g. ArticleDatabase GroupDatabase)
   65.49 +public class Database
   65.50 +{
   65.51 +
   65.52 +  public static final int MAX_RESTARTS = 3;
   65.53 +  
   65.54 +  private static final Map<Thread, Database> instances 
   65.55 +    = new ConcurrentHashMap<Thread, Database>();
   65.56 +  
   65.57 +  /**
   65.58 +   * @return Instance of the current Database backend. Returns null if an error
   65.59 +   * has occurred.
   65.60 +   */
   65.61 +  public static Database getInstance(boolean create)
   65.62 +    throws SQLException
   65.63 +  {
   65.64 +    if(!instances.containsKey(Thread.currentThread()) && create)
   65.65 +    {
   65.66 +      Database db = new Database();
   65.67 +      db.arise();
   65.68 +      instances.put(Thread.currentThread(), db);
   65.69 +      return db;
   65.70 +    }
   65.71 +    else
   65.72 +    {
   65.73 +      return instances.get(Thread.currentThread());
   65.74 +    }
   65.75 +  }
   65.76 +  
   65.77 +  public static Database getInstance()
   65.78 +    throws SQLException
   65.79 +  {
   65.80 +    return getInstance(true);
   65.81 +  }
   65.82 +  
   65.83 +  private Connection        conn = null;
   65.84 +  private PreparedStatement pstmtAddArticle1 = null;
   65.85 +  private PreparedStatement pstmtAddArticle2 = null;
   65.86 +  private PreparedStatement pstmtAddArticle3 = null;
   65.87 +  private PreparedStatement pstmtAddArticle4 = null;
   65.88 +  private PreparedStatement pstmtAddGroup0   = null;
   65.89 +  private PreparedStatement pstmtAddEvent = null;
   65.90 +  private PreparedStatement pstmtCountArticles = null;
   65.91 +  private PreparedStatement pstmtCountGroups   = null;
   65.92 +  private PreparedStatement pstmtDeleteArticle0 = null;
   65.93 +  private PreparedStatement pstmtGetArticle0 = null;
   65.94 +  private PreparedStatement pstmtGetArticle1 = null;
   65.95 +  private PreparedStatement pstmtGetArticleHeaders  = null;
   65.96 +  private PreparedStatement pstmtGetArticleHeads = null;
   65.97 +  private PreparedStatement pstmtGetArticleIDs   = null;
   65.98 +  private PreparedStatement pstmtGetArticleIndex    = null;
   65.99 +  private PreparedStatement pstmtGetConfigValue = null;
  65.100 +  private PreparedStatement pstmtGetEventsCount0 = null;
  65.101 +  private PreparedStatement pstmtGetEventsCount1 = null;
  65.102 +  private PreparedStatement pstmtGetGroupForList = null;
  65.103 +  private PreparedStatement pstmtGetGroup0     = null;
  65.104 +  private PreparedStatement pstmtGetGroup1     = null;
  65.105 +  private PreparedStatement pstmtGetFirstArticleNumber = null;
  65.106 +  private PreparedStatement pstmtGetListForGroup       = null;
  65.107 +  private PreparedStatement pstmtGetLastArticleNumber  = null;
  65.108 +  private PreparedStatement pstmtGetMaxArticleID       = null;
  65.109 +  private PreparedStatement pstmtGetMaxArticleIndex    = null;
  65.110 +  private PreparedStatement pstmtGetPostingsCount      = null;
  65.111 +  private PreparedStatement pstmtGetSubscriptions  = null;
  65.112 +  private PreparedStatement pstmtIsArticleExisting = null;
  65.113 +  private PreparedStatement pstmtIsGroupExisting = null;
  65.114 +  private PreparedStatement pstmtSetConfigValue0 = null;
  65.115 +  private PreparedStatement pstmtSetConfigValue1 = null;
  65.116 +  
  65.117 +  /** How many times the database connection was reinitialized */
  65.118 +  private int restarts = 0;
  65.119 +  
  65.120 +  /**
  65.121 +   * Rises the database: reconnect and recreate all prepared statements.
  65.122 +   * @throws java.lang.SQLException
  65.123 +   */
  65.124 +  private void arise()
  65.125 +    throws SQLException
  65.126 +  {
  65.127 +    try
  65.128 +    {
  65.129 +      // Load database driver
  65.130 +      Class.forName(
  65.131 +              BootstrapConfig.getInstance().get(BootstrapConfig.STORAGE_DBMSDRIVER, "java.lang.Object"));
  65.132 +
  65.133 +      // Establish database connection
  65.134 +      this.conn = DriverManager.getConnection(
  65.135 +              BootstrapConfig.getInstance().get(BootstrapConfig.STORAGE_DATABASE, "<not specified>"),
  65.136 +              BootstrapConfig.getInstance().get(BootstrapConfig.STORAGE_USER, "root"),
  65.137 +              BootstrapConfig.getInstance().get(BootstrapConfig.STORAGE_PASSWORD, ""));
  65.138 +
  65.139 +      this.conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
  65.140 +      if(this.conn.getTransactionIsolation() != Connection.TRANSACTION_SERIALIZABLE)
  65.141 +      {
  65.142 +        Log.msg("Warning: Database is NOT fully serializable!", false);
  65.143 +      }
  65.144 +
  65.145 +      // Prepare statements for method addArticle()
  65.146 +      this.pstmtAddArticle1 = conn.prepareStatement(
  65.147 +        "INSERT INTO articles (article_id, body) VALUES(?, ?)");
  65.148 +      this.pstmtAddArticle2 = conn.prepareStatement(
  65.149 +        "INSERT INTO headers (article_id, header_key, header_value, header_index) " +
  65.150 +        "VALUES (?, ?, ?, ?)");
  65.151 +      this.pstmtAddArticle3 = conn.prepareStatement(
  65.152 +        "INSERT INTO postings (group_id, article_id, article_index)" +
  65.153 +        "VALUES (?, ?, ?)");
  65.154 +      this.pstmtAddArticle4 = conn.prepareStatement(
  65.155 +        "INSERT INTO article_ids (article_id, message_id) VALUES (?, ?)");
  65.156 +
  65.157 +      // Prepare statement for method addStatValue()
  65.158 +      this.pstmtAddEvent = conn.prepareStatement(
  65.159 +        "INSERT INTO events VALUES (?, ?, ?)");
  65.160 +     
  65.161 +      // Prepare statement for method addGroup()
  65.162 +      this.pstmtAddGroup0 = conn.prepareStatement(
  65.163 +        "INSERT INTO groups (name, flags) VALUES (?, ?)");
  65.164 +      
  65.165 +      // Prepare statement for method countArticles()
  65.166 +      this.pstmtCountArticles = conn.prepareStatement(
  65.167 +        "SELECT Count(article_id) FROM article_ids");
  65.168 +      
  65.169 +      // Prepare statement for method countGroups()
  65.170 +      this.pstmtCountGroups = conn.prepareStatement(
  65.171 +        "SELECT Count(group_id) FROM groups WHERE " +
  65.172 +        "flags & " + Group.DELETED + " = 0");
  65.173 +      
  65.174 +      // Prepare statements for method delete(article)
  65.175 +      this.pstmtDeleteArticle0 = conn.prepareStatement(
  65.176 +        "DELETE FROM articles WHERE article_id = " +
  65.177 +        "(SELECT article_id FROM article_ids WHERE message_id = ?)");
  65.178 +
  65.179 +      // Prepare statements for methods getArticle()
  65.180 +      this.pstmtGetArticle0 = conn.prepareStatement(
  65.181 +        "SELECT * FROM articles  WHERE article_id = " +
  65.182 +        "(SELECT article_id FROM article_ids WHERE message_id = ?)");
  65.183 +      this.pstmtGetArticle1 = conn.prepareStatement(
  65.184 +        "SELECT * FROM articles WHERE article_id = " +
  65.185 +        "(SELECT article_id FROM postings WHERE " +
  65.186 +        "article_index = ? AND group_id = ?)");
  65.187 +      
  65.188 +      // Prepare statement for method getArticleHeaders()
  65.189 +      this.pstmtGetArticleHeaders = conn.prepareStatement(
  65.190 +        "SELECT header_key, header_value FROM headers WHERE article_id = ? " +
  65.191 +        "ORDER BY header_index ASC");
  65.192 +      
  65.193 +      this.pstmtGetArticleIDs = conn.prepareStatement(
  65.194 +        "SELECT article_index FROM postings WHERE group_id = ?");
  65.195 +      
  65.196 +      // Prepare statement for method getArticleIndex
  65.197 +      this.pstmtGetArticleIndex = conn.prepareStatement(
  65.198 +              "SELECT article_index FROM postings WHERE " +
  65.199 +              "article_id = (SELECT article_id FROM article_ids " +
  65.200 +              "WHERE message_id = ?) " +
  65.201 +              " AND group_id = ?");
  65.202 +
  65.203 +      // Prepare statements for method getArticleHeads()
  65.204 +      this.pstmtGetArticleHeads = conn.prepareStatement(
  65.205 +        "SELECT article_id, article_index FROM postings WHERE " +
  65.206 +        "postings.group_id = ? AND article_index >= ? AND " +
  65.207 +        "article_index <= ?");
  65.208 +
  65.209 +      // Prepare statements for method getConfigValue()
  65.210 +      this.pstmtGetConfigValue = conn.prepareStatement(
  65.211 +        "SELECT config_value FROM config WHERE config_key = ?");
  65.212 +
  65.213 +      // Prepare statements for method getEventsCount()
  65.214 +      this.pstmtGetEventsCount0 = conn.prepareStatement(
  65.215 +        "SELECT Count(*) FROM events WHERE event_key = ? AND " +
  65.216 +        "event_time >= ? AND event_time < ?");
  65.217 +
  65.218 +      this.pstmtGetEventsCount1 = conn.prepareStatement(
  65.219 +        "SELECT Count(*) FROM events WHERE event_key = ? AND " +
  65.220 +        "event_time >= ? AND event_time < ? AND group_id = ?");
  65.221 +      
  65.222 +      // Prepare statement for method getGroupForList()
  65.223 +      this.pstmtGetGroupForList = conn.prepareStatement(
  65.224 +        "SELECT name FROM groups INNER JOIN groups2list " +
  65.225 +        "ON groups.group_id = groups2list.group_id " +
  65.226 +        "WHERE groups2list.listaddress = ?");
  65.227 +
  65.228 +      // Prepare statement for method getGroup()
  65.229 +      this.pstmtGetGroup0 = conn.prepareStatement(
  65.230 +        "SELECT group_id, flags FROM groups WHERE Name = ?");
  65.231 +      this.pstmtGetGroup1 = conn.prepareStatement(
  65.232 +        "SELECT name FROM groups WHERE group_id = ?");
  65.233 +
  65.234 +      // Prepare statement for method getLastArticleNumber()
  65.235 +      this.pstmtGetLastArticleNumber = conn.prepareStatement(
  65.236 +        "SELECT Max(article_index) FROM postings WHERE group_id = ?");
  65.237 +
  65.238 +      // Prepare statement for method getListForGroup()
  65.239 +      this.pstmtGetListForGroup = conn.prepareStatement(
  65.240 +        "SELECT listaddress FROM groups2list INNER JOIN groups " +
  65.241 +        "ON groups.group_id = groups2list.group_id WHERE name = ?");
  65.242 +
  65.243 +      // Prepare statement for method getMaxArticleID()
  65.244 +      this.pstmtGetMaxArticleID = conn.prepareStatement(
  65.245 +        "SELECT Max(article_id) FROM articles");
  65.246 +      
  65.247 +      // Prepare statement for method getMaxArticleIndex()
  65.248 +      this.pstmtGetMaxArticleIndex = conn.prepareStatement(
  65.249 +        "SELECT Max(article_index) FROM postings WHERE group_id = ?");
  65.250 +      
  65.251 +      // Prepare statement for method getFirstArticleNumber()
  65.252 +      this.pstmtGetFirstArticleNumber = conn.prepareStatement(
  65.253 +        "SELECT Min(article_index) FROM postings WHERE group_id = ?");
  65.254 +      
  65.255 +      // Prepare statement for method getPostingsCount()
  65.256 +      this.pstmtGetPostingsCount = conn.prepareStatement(
  65.257 +        "SELECT Count(*) FROM postings NATURAL JOIN groups " +
  65.258 +        "WHERE groups.name = ?");
  65.259 +      
  65.260 +      // Prepare statement for method getSubscriptions()
  65.261 +      this.pstmtGetSubscriptions = conn.prepareStatement(
  65.262 +        "SELECT host, port, name FROM peers NATURAL JOIN " +
  65.263 +        "peer_subscriptions NATURAL JOIN groups WHERE feedtype = ?");
  65.264 +      
  65.265 +      // Prepare statement for method isArticleExisting()
  65.266 +      this.pstmtIsArticleExisting = conn.prepareStatement(
  65.267 +        "SELECT Count(article_id) FROM article_ids WHERE message_id = ?");
  65.268 +      
  65.269 +      // Prepare statement for method isGroupExisting()
  65.270 +      this.pstmtIsGroupExisting = conn.prepareStatement(
  65.271 +        "SELECT * FROM groups WHERE name = ?");
  65.272 +      
  65.273 +      // Prepare statement for method setConfigValue()
  65.274 +      this.pstmtSetConfigValue0 = conn.prepareStatement(
  65.275 +        "DELETE FROM config WHERE config_key = ?");
  65.276 +      this.pstmtSetConfigValue1 = conn.prepareStatement(
  65.277 +        "INSERT INTO config VALUES(?, ?)");
  65.278 +    }
  65.279 +    catch(ClassNotFoundException ex)
  65.280 +    {
  65.281 +      throw new Error("JDBC Driver not found!", ex);
  65.282 +    }
  65.283 +  }
  65.284 +  
  65.285 +  /**
  65.286 +   * Adds an article to the database.
  65.287 +   * @param article
  65.288 +   * @return
  65.289 +   * @throws java.sql.SQLException
  65.290 +   */
  65.291 +  public void addArticle(final Article article)
  65.292 +    throws SQLException
  65.293 +  {
  65.294 +    try
  65.295 +    {
  65.296 +      this.conn.setAutoCommit(false);
  65.297 +
  65.298 +      int newArticleID = getMaxArticleID() + 1;
  65.299 +
  65.300 +      // Fill prepared statement with values;
  65.301 +      // writes body to article table
  65.302 +      pstmtAddArticle1.setInt(1, newArticleID);
  65.303 +      pstmtAddArticle1.setBytes(2, article.getBody().getBytes());
  65.304 +      pstmtAddArticle1.execute();
  65.305 +
  65.306 +      // Add headers
  65.307 +      Enumeration headers = article.getAllHeaders();
  65.308 +      for(int n = 0; headers.hasMoreElements(); n++)
  65.309 +      {
  65.310 +        Header header = (Header)headers.nextElement();
  65.311 +        pstmtAddArticle2.setInt(1, newArticleID);
  65.312 +        pstmtAddArticle2.setString(2, header.getName().toLowerCase());
  65.313 +        pstmtAddArticle2.setString(3, 
  65.314 +          header.getValue().replaceAll("[\r\n]", ""));
  65.315 +        pstmtAddArticle2.setInt(4, n);
  65.316 +        pstmtAddArticle2.execute();
  65.317 +      }
  65.318 +      
  65.319 +      // For each newsgroup add a reference
  65.320 +      List<Group> groups = article.getGroups();
  65.321 +      for(Group group : groups)
  65.322 +      {
  65.323 +        pstmtAddArticle3.setLong(1, group.getID());
  65.324 +        pstmtAddArticle3.setInt(2, newArticleID);
  65.325 +        pstmtAddArticle3.setLong(3, getMaxArticleIndex(group.getID()) + 1);
  65.326 +        pstmtAddArticle3.execute();
  65.327 +      }
  65.328 +      
  65.329 +      // Write message-id to article_ids table
  65.330 +      this.pstmtAddArticle4.setInt(1, newArticleID);
  65.331 +      this.pstmtAddArticle4.setString(2, article.getMessageID());
  65.332 +      this.pstmtAddArticle4.execute();
  65.333 +
  65.334 +      this.conn.commit();
  65.335 +      this.conn.setAutoCommit(true);
  65.336 +
  65.337 +      this.restarts = 0; // Reset error count
  65.338 +    }
  65.339 +    catch(SQLException ex)
  65.340 +    {
  65.341 +      try
  65.342 +      {
  65.343 +        this.conn.rollback();  // Rollback changes
  65.344 +      }
  65.345 +      catch(SQLException ex2)
  65.346 +      {
  65.347 +        Log.msg("Rollback of addArticle() failed: " + ex2, false);
  65.348 +      }
  65.349 +      
  65.350 +      try
  65.351 +      {
  65.352 +        this.conn.setAutoCommit(true); // and release locks
  65.353 +      }
  65.354 +      catch(SQLException ex2)
  65.355 +      {
  65.356 +        Log.msg("setAutoCommit(true) of addArticle() failed: " + ex2, false);
  65.357 +      }
  65.358 +
  65.359 +      restartConnection(ex);
  65.360 +      addArticle(article);
  65.361 +    }
  65.362 +  }
  65.363 +  
  65.364 +  /**
  65.365 +   * Adds a group to the Database. This method is not accessible via NNTP.
  65.366 +   * @param name
  65.367 +   * @throws java.sql.SQLException
  65.368 +   */
  65.369 +  public void addGroup(String name, int flags)
  65.370 +    throws SQLException
  65.371 +  {
  65.372 +    try
  65.373 +    {
  65.374 +      this.conn.setAutoCommit(false);
  65.375 +      pstmtAddGroup0.setString(1, name);
  65.376 +      pstmtAddGroup0.setInt(2, flags);
  65.377 +
  65.378 +      pstmtAddGroup0.executeUpdate();
  65.379 +      this.conn.commit();
  65.380 +      this.conn.setAutoCommit(true);
  65.381 +      this.restarts = 0; // Reset error count
  65.382 +    }
  65.383 +    catch(SQLException ex)
  65.384 +    {
  65.385 +      this.conn.rollback();
  65.386 +      this.conn.setAutoCommit(true);
  65.387 +      restartConnection(ex);
  65.388 +      addGroup(name, flags);
  65.389 +    }
  65.390 +  }
  65.391 +  
  65.392 +  public void addEvent(long time, byte type, long gid)
  65.393 +    throws SQLException
  65.394 +  {
  65.395 +    try
  65.396 +    {
  65.397 +      this.conn.setAutoCommit(false);
  65.398 +      this.pstmtAddEvent.setLong(1, time);
  65.399 +      this.pstmtAddEvent.setInt(2, type);
  65.400 +      this.pstmtAddEvent.setLong(3, gid);
  65.401 +      this.pstmtAddEvent.executeUpdate();
  65.402 +      this.conn.commit();
  65.403 +      this.conn.setAutoCommit(true);
  65.404 +      this.restarts = 0;
  65.405 +    }
  65.406 +    catch(SQLException ex)
  65.407 +    {
  65.408 +      this.conn.rollback();
  65.409 +      this.conn.setAutoCommit(true);
  65.410 +
  65.411 +      restartConnection(ex);
  65.412 +      addEvent(time, type, gid);
  65.413 +    }
  65.414 +  }
  65.415 +  
  65.416 +  public int countArticles()
  65.417 +    throws SQLException
  65.418 +  {
  65.419 +    ResultSet rs = null;
  65.420 +
  65.421 +    try
  65.422 +    {
  65.423 +      rs = this.pstmtCountArticles.executeQuery();
  65.424 +      if(rs.next())
  65.425 +      {
  65.426 +        return rs.getInt(1);
  65.427 +      }
  65.428 +      else
  65.429 +      {
  65.430 +        return -1;
  65.431 +      }
  65.432 +    }
  65.433 +    catch(SQLException ex)
  65.434 +    {
  65.435 +      restartConnection(ex);
  65.436 +      return countArticles();
  65.437 +    }
  65.438 +    finally
  65.439 +    {
  65.440 +      if(rs != null)
  65.441 +      {
  65.442 +        rs.close();
  65.443 +        restarts = 0;
  65.444 +      }
  65.445 +    }
  65.446 +  }
  65.447 +  
  65.448 +  public int countGroups()
  65.449 +    throws SQLException
  65.450 +  {
  65.451 +    ResultSet rs = null;
  65.452 +
  65.453 +    try
  65.454 +    {
  65.455 +      rs = this.pstmtCountGroups.executeQuery();
  65.456 +      if(rs.next())
  65.457 +      {
  65.458 +        return rs.getInt(1);
  65.459 +      }
  65.460 +      else
  65.461 +      {
  65.462 +        return -1;
  65.463 +      }
  65.464 +    }
  65.465 +    catch(SQLException ex)
  65.466 +    {
  65.467 +      restartConnection(ex);
  65.468 +      return countGroups();
  65.469 +    }
  65.470 +    finally
  65.471 +    {
  65.472 +      if(rs != null)
  65.473 +      {
  65.474 +        rs.close();
  65.475 +        restarts = 0;
  65.476 +      }
  65.477 +    }
  65.478 +  }
  65.479 +  
  65.480 +  public void delete(final String messageID)
  65.481 +    throws SQLException
  65.482 +  {
  65.483 +    try
  65.484 +    {
  65.485 +      this.conn.setAutoCommit(false);
  65.486 +      
  65.487 +      this.pstmtDeleteArticle0.setString(1, messageID);
  65.488 +      ResultSet rs = this.pstmtDeleteArticle0.executeQuery();
  65.489 +      rs.next();
  65.490 +      
  65.491 +      // We trust the ON DELETE CASCADE functionality to delete
  65.492 +      // orphaned references
  65.493 +      
  65.494 +      this.conn.commit();
  65.495 +      this.conn.setAutoCommit(true);
  65.496 +    }
  65.497 +    catch(SQLException ex)
  65.498 +    {
  65.499 +      throw ex;
  65.500 +    }
  65.501 +  }
  65.502 +  
  65.503 +  public Article getArticle(String messageID)
  65.504 +    throws SQLException
  65.505 +  {
  65.506 +    ResultSet rs = null;
  65.507 +    try
  65.508 +    {
  65.509 +      pstmtGetArticle0.setString(1, messageID);
  65.510 +      rs = pstmtGetArticle0.executeQuery();
  65.511 +
  65.512 +      if(!rs.next())
  65.513 +      {
  65.514 +        return null;
  65.515 +      }
  65.516 +      else
  65.517 +      {
  65.518 +        String body     = new String(rs.getBytes("body"));
  65.519 +        String headers  = getArticleHeaders(rs.getInt("article_id"));
  65.520 +        return new Article(headers, body);
  65.521 +      }
  65.522 +    }
  65.523 +    catch(SQLException ex)
  65.524 +    {
  65.525 +      restartConnection(ex);
  65.526 +      return getArticle(messageID);
  65.527 +    }
  65.528 +    finally
  65.529 +    {
  65.530 +      if(rs != null)
  65.531 +      {
  65.532 +        rs.close();
  65.533 +        restarts = 0; // Reset error count
  65.534 +      }
  65.535 +    }
  65.536 +  }
  65.537 +  
  65.538 +  /**
  65.539 +   * Retrieves an article by its ID.
  65.540 +   * @param articleID
  65.541 +   * @return
  65.542 +   * @throws java.sql.SQLException
  65.543 +   */
  65.544 +  public Article getArticle(long articleIndex, long gid)
  65.545 +    throws SQLException
  65.546 +  {  
  65.547 +    ResultSet rs = null;
  65.548 +
  65.549 +    try
  65.550 +    {
  65.551 +      this.pstmtGetArticle1.setLong(1, articleIndex);
  65.552 +      this.pstmtGetArticle1.setLong(2, gid);
  65.553 +
  65.554 +      rs = this.pstmtGetArticle1.executeQuery();
  65.555 +
  65.556 +      if(rs.next())
  65.557 +      {
  65.558 +        String body    = new String(rs.getBytes("body"));
  65.559 +        String headers = getArticleHeaders(rs.getInt("article_id"));
  65.560 +        return new Article(headers, body);
  65.561 +      }
  65.562 +      else
  65.563 +      {
  65.564 +        return null;
  65.565 +      }
  65.566 +    }
  65.567 +    catch(SQLException ex)
  65.568 +    {
  65.569 +      restartConnection(ex);
  65.570 +      return getArticle(articleIndex, gid);
  65.571 +    }
  65.572 +    finally
  65.573 +    {
  65.574 +      if(rs != null)
  65.575 +      {
  65.576 +        rs.close();
  65.577 +        restarts = 0;
  65.578 +      }
  65.579 +    }
  65.580 +  }
  65.581 +  
  65.582 +  public String getArticleHeaders(long articleID)
  65.583 +    throws SQLException
  65.584 +  {
  65.585 +    ResultSet rs = null;
  65.586 +    
  65.587 +    try
  65.588 +    {
  65.589 +      this.pstmtGetArticleHeaders.setLong(1, articleID);
  65.590 +      rs = this.pstmtGetArticleHeaders.executeQuery();
  65.591 +      
  65.592 +      StringBuilder buf = new StringBuilder();
  65.593 +      if(rs.next())
  65.594 +      {
  65.595 +        for(;;)
  65.596 +        {
  65.597 +          buf.append(rs.getString(1)); // key
  65.598 +          buf.append(": ");
  65.599 +          String foldedValue = MimeUtility.fold(0, rs.getString(2));
  65.600 +          buf.append(foldedValue); // value
  65.601 +          if(rs.next())
  65.602 +          {
  65.603 +            buf.append("\r\n");
  65.604 +          }
  65.605 +          else
  65.606 +          {
  65.607 +            break;
  65.608 +          }
  65.609 +        }
  65.610 +      }
  65.611 +      
  65.612 +      return buf.toString();
  65.613 +    }
  65.614 +    catch(SQLException ex)
  65.615 +    {
  65.616 +      restartConnection(ex);
  65.617 +      return getArticleHeaders(articleID);
  65.618 +    }
  65.619 +    finally
  65.620 +    {
  65.621 +      if(rs != null)
  65.622 +        rs.close();
  65.623 +    }
  65.624 +  }
  65.625 +  
  65.626 +  public long getArticleIndex(Article article, Group group)
  65.627 +    throws SQLException
  65.628 +  {
  65.629 +    ResultSet rs = null;
  65.630 +
  65.631 +    try
  65.632 +    {
  65.633 +      this.pstmtGetArticleIndex.setString(1, article.getMessageID());
  65.634 +      this.pstmtGetArticleIndex.setLong(2, group.getID());
  65.635 +      
  65.636 +      rs = this.pstmtGetArticleIndex.executeQuery();
  65.637 +      if(rs.next())
  65.638 +      {
  65.639 +        return rs.getLong(1);
  65.640 +      }
  65.641 +      else
  65.642 +      {
  65.643 +        return -1;
  65.644 +      }
  65.645 +    }
  65.646 +    catch(SQLException ex)
  65.647 +    {
  65.648 +      restartConnection(ex);
  65.649 +      return getArticleIndex(article, group);
  65.650 +    }
  65.651 +    finally
  65.652 +    {
  65.653 +      if(rs != null)
  65.654 +        rs.close();
  65.655 +    }
  65.656 +  }
  65.657 +  
  65.658 +  /**
  65.659 +   * Returns a list of Long/Article Pairs.
  65.660 +   * @throws java.sql.SQLException
  65.661 +   */
  65.662 +  public List<Pair<Long, ArticleHead>> getArticleHeads(Group group, int first, int last)
  65.663 +    throws SQLException
  65.664 +  {
  65.665 +    ResultSet rs = null;
  65.666 +
  65.667 +    try
  65.668 +    {
  65.669 +      this.pstmtGetArticleHeads.setLong(1, group.getID());
  65.670 +      this.pstmtGetArticleHeads.setInt(2, first);
  65.671 +      this.pstmtGetArticleHeads.setInt(3, last);
  65.672 +      rs = pstmtGetArticleHeads.executeQuery();
  65.673 +
  65.674 +      List<Pair<Long, ArticleHead>> articles 
  65.675 +        = new ArrayList<Pair<Long, ArticleHead>>();
  65.676 +
  65.677 +      while (rs.next())
  65.678 +      {
  65.679 +        long aid  = rs.getLong("article_id");
  65.680 +        long aidx = rs.getLong("article_index");
  65.681 +        String headers = getArticleHeaders(aid);
  65.682 +        articles.add(new Pair<Long, ArticleHead>(aidx, 
  65.683 +                        new ArticleHead(headers)));
  65.684 +      }
  65.685 +
  65.686 +      return articles;
  65.687 +    }
  65.688 +    catch(SQLException ex)
  65.689 +    {
  65.690 +      restartConnection(ex);
  65.691 +      return getArticleHeads(group, first, last);
  65.692 +    }
  65.693 +    finally
  65.694 +    {
  65.695 +      if(rs != null)
  65.696 +        rs.close();
  65.697 +    }
  65.698 +  }
  65.699 +  
  65.700 +  public List<Long> getArticleNumbers(long gid)
  65.701 +    throws SQLException
  65.702 +  {
  65.703 +    ResultSet rs = null;
  65.704 +    try
  65.705 +    {
  65.706 +      List<Long> ids = new ArrayList<Long>();
  65.707 +      this.pstmtGetArticleIDs.setLong(1, gid);
  65.708 +      rs = this.pstmtGetArticleIDs.executeQuery();
  65.709 +      while(rs.next())
  65.710 +      {
  65.711 +        ids.add(rs.getLong(1));
  65.712 +      }
  65.713 +      return ids;
  65.714 +    }
  65.715 +    catch(SQLException ex)
  65.716 +    {
  65.717 +      restartConnection(ex);
  65.718 +      return getArticleNumbers(gid);
  65.719 +    }
  65.720 +    finally
  65.721 +    {
  65.722 +      if(rs != null)
  65.723 +      {
  65.724 +        rs.close();
  65.725 +        restarts = 0; // Clear the restart count after successful request
  65.726 +      }
  65.727 +    }
  65.728 +  }
  65.729 +  
  65.730 +  public String getConfigValue(String key)
  65.731 +    throws SQLException
  65.732 +  {
  65.733 +    ResultSet rs = null;
  65.734 +    try
  65.735 +    {
  65.736 +      this.pstmtGetConfigValue.setString(1, key);
  65.737 +
  65.738 +      rs = this.pstmtGetConfigValue.executeQuery();
  65.739 +      if(rs.next())
  65.740 +      {
  65.741 +        return rs.getString(1); // First data on index 1 not 0
  65.742 +      }
  65.743 +      else
  65.744 +      {
  65.745 +        return null;
  65.746 +      }
  65.747 +    }
  65.748 +    catch(SQLException ex)
  65.749 +    {
  65.750 +      restartConnection(ex);
  65.751 +      return getConfigValue(key);
  65.752 +    }
  65.753 +    finally
  65.754 +    {
  65.755 +      if(rs != null)
  65.756 +      {
  65.757 +        rs.close();
  65.758 +        restarts = 0; // Clear the restart count after successful request
  65.759 +      }
  65.760 +    }
  65.761 +  }
  65.762 +  
  65.763 +  public int getEventsCount(byte type, long start, long end, Group group)
  65.764 +    throws SQLException
  65.765 +  {
  65.766 +    ResultSet rs = null;
  65.767 +    
  65.768 +    try
  65.769 +    {
  65.770 +      if(group == null)
  65.771 +      {
  65.772 +        this.pstmtGetEventsCount0.setInt(1, type);
  65.773 +        this.pstmtGetEventsCount0.setLong(2, start);
  65.774 +        this.pstmtGetEventsCount0.setLong(3, end);
  65.775 +        rs = this.pstmtGetEventsCount0.executeQuery();
  65.776 +      }
  65.777 +      else
  65.778 +      {
  65.779 +        this.pstmtGetEventsCount1.setInt(1, type);
  65.780 +        this.pstmtGetEventsCount1.setLong(2, start);
  65.781 +        this.pstmtGetEventsCount1.setLong(3, end);
  65.782 +        this.pstmtGetEventsCount1.setLong(4, group.getID());
  65.783 +        rs = this.pstmtGetEventsCount1.executeQuery();
  65.784 +      }
  65.785 +      
  65.786 +      if(rs.next())
  65.787 +      {
  65.788 +        return rs.getInt(1);
  65.789 +      }
  65.790 +      else
  65.791 +      {
  65.792 +        return -1;
  65.793 +      }
  65.794 +    }
  65.795 +    catch(SQLException ex)
  65.796 +    {
  65.797 +      restartConnection(ex);
  65.798 +      return getEventsCount(type, start, end, group);
  65.799 +    }
  65.800 +    finally
  65.801 +    {
  65.802 +      if(rs != null)
  65.803 +        rs.close();
  65.804 +    }
  65.805 +  }
  65.806 +  
  65.807 +  /**
  65.808 +   * Reads all Groups from the Database.
  65.809 +   * @return
  65.810 +   * @throws java.sql.SQLException
  65.811 +   */
  65.812 +  public List<Group> getGroups()
  65.813 +    throws SQLException
  65.814 +  {
  65.815 +    ResultSet   rs;
  65.816 +    List<Group> buffer = new ArrayList<Group>();
  65.817 +    Statement   stmt   = null;
  65.818 +
  65.819 +    try
  65.820 +    {
  65.821 +      stmt = conn.createStatement();
  65.822 +      rs = stmt.executeQuery("SELECT * FROM groups ORDER BY name");
  65.823 +
  65.824 +      while(rs.next())
  65.825 +      {
  65.826 +        String name  = rs.getString("name");
  65.827 +        long   id    = rs.getLong("group_id");
  65.828 +        int    flags = rs.getInt("flags");
  65.829 +        
  65.830 +        Group group = new Group(name, id, flags);
  65.831 +        buffer.add(group);
  65.832 +      }
  65.833 +
  65.834 +      return buffer;
  65.835 +    }
  65.836 +    catch(SQLException ex)
  65.837 +    {
  65.838 +      restartConnection(ex);
  65.839 +      return getGroups();
  65.840 +    }
  65.841 +    finally
  65.842 +    {
  65.843 +      if(stmt != null)
  65.844 +        stmt.close(); // Implicitely closes ResultSets
  65.845 +    }
  65.846 +  }
  65.847 +  
  65.848 +  public String getGroupForList(InternetAddress listAddress)
  65.849 +    throws SQLException
  65.850 +  {
  65.851 +    ResultSet rs = null;
  65.852 +    
  65.853 +    try
  65.854 +    {
  65.855 +      this.pstmtGetGroupForList.setString(1, listAddress.getAddress());
  65.856 +
  65.857 +      rs = this.pstmtGetGroupForList.executeQuery();
  65.858 +      if (rs.next())
  65.859 +      {
  65.860 +        return rs.getString(1);
  65.861 +      }
  65.862 +      else
  65.863 +      {
  65.864 +        return null;
  65.865 +      }
  65.866 +    }
  65.867 +    catch(SQLException ex)
  65.868 +    {
  65.869 +      restartConnection(ex);
  65.870 +      return getGroupForList(listAddress);
  65.871 +    }
  65.872 +    finally
  65.873 +    {
  65.874 +      if(rs != null)
  65.875 +        rs.close();
  65.876 +    }
  65.877 +  }
  65.878 +  
  65.879 +  /**
  65.880 +   * Returns the Group that is identified by the name.
  65.881 +   * @param name
  65.882 +   * @return
  65.883 +   * @throws java.sql.SQLException
  65.884 +   */
  65.885 +  public Group getGroup(String name)
  65.886 +    throws SQLException
  65.887 +  {
  65.888 +    ResultSet rs = null;
  65.889 +    
  65.890 +    try
  65.891 +    {
  65.892 +      this.pstmtGetGroup0.setString(1, name);
  65.893 +      rs = this.pstmtGetGroup0.executeQuery();
  65.894 +
  65.895 +      if (!rs.next())
  65.896 +      {
  65.897 +        return null;
  65.898 +      }
  65.899 +      else
  65.900 +      {
  65.901 +        long id = rs.getLong("group_id");
  65.902 +        int flags = rs.getInt("flags");
  65.903 +        return new Group(name, id, flags);
  65.904 +      }
  65.905 +    }
  65.906 +    catch(SQLException ex)
  65.907 +    {
  65.908 +      restartConnection(ex);
  65.909 +      return getGroup(name);
  65.910 +    }
  65.911 +    finally
  65.912 +    {
  65.913 +      if(rs != null)
  65.914 +        rs.close();
  65.915 +    }
  65.916 +  }
  65.917 +  
  65.918 +  public String getListForGroup(String group)
  65.919 +    throws SQLException
  65.920 +  {
  65.921 +    ResultSet rs = null;
  65.922 +
  65.923 +    try
  65.924 +    {
  65.925 +      this.pstmtGetListForGroup.setString(1, group);
  65.926 +      rs = this.pstmtGetListForGroup.executeQuery();
  65.927 +      if (rs.next())
  65.928 +      {
  65.929 +        return rs.getString(1);
  65.930 +      }
  65.931 +      else
  65.932 +      {
  65.933 +        return null;
  65.934 +      }
  65.935 +    }
  65.936 +    catch(SQLException ex)
  65.937 +    {
  65.938 +      restartConnection(ex);
  65.939 +      return getListForGroup(group);
  65.940 +    }
  65.941 +    finally
  65.942 +    {
  65.943 +      if(rs != null)
  65.944 +        rs.close();
  65.945 +    }
  65.946 +  }
  65.947 +  
  65.948 +  private int getMaxArticleIndex(long groupID)
  65.949 +    throws SQLException
  65.950 +  {
  65.951 +    ResultSet rs    = null;
  65.952 +
  65.953 +    try
  65.954 +    {
  65.955 +      this.pstmtGetMaxArticleIndex.setLong(1, groupID);
  65.956 +      rs = this.pstmtGetMaxArticleIndex.executeQuery();
  65.957 +
  65.958 +      int maxIndex = 0;
  65.959 +      if (rs.next())
  65.960 +      {
  65.961 +        maxIndex = rs.getInt(1);
  65.962 +      }
  65.963 +
  65.964 +      return maxIndex;
  65.965 +    }
  65.966 +    catch(SQLException ex)
  65.967 +    {
  65.968 +      restartConnection(ex);
  65.969 +      return getMaxArticleIndex(groupID);
  65.970 +    }
  65.971 +    finally
  65.972 +    {
  65.973 +      if(rs != null)
  65.974 +        rs.close();
  65.975 +    }
  65.976 +  }
  65.977 +  
  65.978 +  private int getMaxArticleID()
  65.979 +    throws SQLException
  65.980 +  {
  65.981 +    ResultSet rs    = null;
  65.982 +
  65.983 +    try
  65.984 +    {
  65.985 +      rs = this.pstmtGetMaxArticleID.executeQuery();
  65.986 +
  65.987 +      int maxIndex = 0;
  65.988 +      if (rs.next())
  65.989 +      {
  65.990 +        maxIndex = rs.getInt(1);
  65.991 +      }
  65.992 +
  65.993 +      return maxIndex;
  65.994 +    }
  65.995 +    catch(SQLException ex)
  65.996 +    {
  65.997 +      restartConnection(ex);
  65.998 +      return getMaxArticleID();
  65.999 +    }
 65.1000 +    finally
 65.1001 +    {
 65.1002 +      if(rs != null)
 65.1003 +        rs.close();
 65.1004 +    }
 65.1005 +  }
 65.1006 +  
 65.1007 +  public int getLastArticleNumber(Group group)
 65.1008 +    throws SQLException
 65.1009 +  {
 65.1010 +    ResultSet rs = null;
 65.1011 +
 65.1012 +    try
 65.1013 +    {
 65.1014 +      this.pstmtGetLastArticleNumber.setLong(1, group.getID());
 65.1015 +      rs = this.pstmtGetLastArticleNumber.executeQuery();
 65.1016 +      if (rs.next())
 65.1017 +      {
 65.1018 +        return rs.getInt(1);
 65.1019 +      }
 65.1020 +      else
 65.1021 +      {
 65.1022 +        return 0;
 65.1023 +      }
 65.1024 +    }
 65.1025 +    catch(SQLException ex)
 65.1026 +    {
 65.1027 +      restartConnection(ex);
 65.1028 +      return getLastArticleNumber(group);
 65.1029 +    }
 65.1030 +    finally
 65.1031 +    {
 65.1032 +      if(rs != null)
 65.1033 +        rs.close();
 65.1034 +    }
 65.1035 +  }
 65.1036 +  
 65.1037 +  public int getFirstArticleNumber(Group group)
 65.1038 +    throws SQLException
 65.1039 +  {
 65.1040 +    ResultSet rs = null;
 65.1041 +    try
 65.1042 +    {
 65.1043 +      this.pstmtGetFirstArticleNumber.setLong(1, group.getID());
 65.1044 +      rs = this.pstmtGetFirstArticleNumber.executeQuery();
 65.1045 +      if(rs.next())
 65.1046 +      {
 65.1047 +        return rs.getInt(1);
 65.1048 +      }
 65.1049 +      else
 65.1050 +      {
 65.1051 +        return 0;
 65.1052 +      }
 65.1053 +    }
 65.1054 +    catch(SQLException ex)
 65.1055 +    {
 65.1056 +      restartConnection(ex);
 65.1057 +      return getFirstArticleNumber(group);
 65.1058 +    }
 65.1059 +    finally
 65.1060 +    {
 65.1061 +      if(rs != null)
 65.1062 +        rs.close();
 65.1063 +    }
 65.1064 +  }
 65.1065 +  
 65.1066 +  /**
 65.1067 +   * Returns a group name identified by the given id.
 65.1068 +   * @param id
 65.1069 +   * @return
 65.1070 +   * @throws java.sql.SQLException
 65.1071 +   */
 65.1072 +  public String getGroup(int id)
 65.1073 +    throws SQLException
 65.1074 +  {
 65.1075 +    ResultSet rs = null;
 65.1076 +
 65.1077 +    try
 65.1078 +    {
 65.1079 +      this.pstmtGetGroup1.setInt(1, id);
 65.1080 +      rs = this.pstmtGetGroup1.executeQuery();
 65.1081 +
 65.1082 +      if (rs.next())
 65.1083 +      {
 65.1084 +        return rs.getString(1);
 65.1085 +      }
 65.1086 +      else
 65.1087 +      {
 65.1088 +        return null;
 65.1089 +      }
 65.1090 +    }
 65.1091 +    catch(SQLException ex)
 65.1092 +    {
 65.1093 +      restartConnection(ex);
 65.1094 +      return getGroup(id);
 65.1095 +    }
 65.1096 +    finally
 65.1097 +    {
 65.1098 +      if(rs != null)
 65.1099 +        rs.close();
 65.1100 +    }
 65.1101 +  }
 65.1102 +  
 65.1103 +  public double getNumberOfEventsPerHour(int key, long gid)
 65.1104 +    throws SQLException
 65.1105 +  {
 65.1106 +    String gidquery = "";
 65.1107 +    if(gid >= 0)
 65.1108 +    {
 65.1109 +      gidquery = " AND group_id = " + gid;
 65.1110 +    }
 65.1111 +    
 65.1112 +    Statement stmt = null;
 65.1113 +    ResultSet rs   = null;
 65.1114 +    
 65.1115 +    try
 65.1116 +    {
 65.1117 +      stmt = this.conn.createStatement();
 65.1118 +      rs = stmt.executeQuery("SELECT Count(*) / (Max(event_time) - Min(event_time))" +
 65.1119 +        " * 1000 * 60 * 60 FROM events WHERE event_key = " + key + gidquery);
 65.1120 +      
 65.1121 +      if(rs.next())
 65.1122 +      {
 65.1123 +        restarts = 0; // reset error count
 65.1124 +        return rs.getDouble(1);
 65.1125 +      }
 65.1126 +      else
 65.1127 +      {
 65.1128 +        return Double.NaN;
 65.1129 +      }
 65.1130 +    }
 65.1131 +    catch(SQLException ex)
 65.1132 +    {
 65.1133 +      restartConnection(ex);
 65.1134 +      return getNumberOfEventsPerHour(key, gid);
 65.1135 +    }
 65.1136 +    finally
 65.1137 +    {
 65.1138 +      if(stmt != null)
 65.1139 +      {
 65.1140 +        stmt.close();
 65.1141 +      }
 65.1142 +      
 65.1143 +      if(rs != null)
 65.1144 +      {
 65.1145 +        rs.close();
 65.1146 +      }
 65.1147 +    }
 65.1148 +  }
 65.1149 +  
 65.1150 +  public int getPostingsCount(String groupname)
 65.1151 +    throws SQLException
 65.1152 +  {
 65.1153 +    ResultSet rs = null;
 65.1154 +    
 65.1155 +    try
 65.1156 +    {
 65.1157 +      this.pstmtGetPostingsCount.setString(1, groupname);
 65.1158 +      rs = this.pstmtGetPostingsCount.executeQuery();
 65.1159 +      if(rs.next())
 65.1160 +      {
 65.1161 +        return rs.getInt(1);
 65.1162 +      }
 65.1163 +      else
 65.1164 +      {
 65.1165 +        Log.msg("Warning: Count on postings return nothing!", true);
 65.1166 +        return 0;
 65.1167 +      }
 65.1168 +    }
 65.1169 +    catch(SQLException ex)
 65.1170 +    {
 65.1171 +      restartConnection(ex);
 65.1172 +      return getPostingsCount(groupname);
 65.1173 +    }
 65.1174 +    finally
 65.1175 +    {
 65.1176 +      if(rs != null)
 65.1177 +        rs.close();
 65.1178 +    }
 65.1179 +  }
 65.1180 +  
 65.1181 +  public List<Subscription> getSubscriptions(int feedtype)
 65.1182 +    throws SQLException
 65.1183 +  {
 65.1184 +    ResultSet rs = null;
 65.1185 +    
 65.1186 +    try
 65.1187 +    {
 65.1188 +      List<Subscription> subs = new ArrayList<Subscription>();
 65.1189 +      this.pstmtGetSubscriptions.setInt(1, feedtype);
 65.1190 +      rs = this.pstmtGetSubscriptions.executeQuery();
 65.1191 +      
 65.1192 +      while(rs.next())
 65.1193 +      {
 65.1194 +        String host  = rs.getString("host");
 65.1195 +        String group = rs.getString("name");
 65.1196 +        int    port  = rs.getInt("port");
 65.1197 +        subs.add(new Subscription(host, port, feedtype, group));
 65.1198 +      }
 65.1199 +      
 65.1200 +      return subs;
 65.1201 +    }
 65.1202 +    catch(SQLException ex)
 65.1203 +    {
 65.1204 +      restartConnection(ex);
 65.1205 +      return getSubscriptions(feedtype);
 65.1206 +    }
 65.1207 +    finally
 65.1208 +    {
 65.1209 +      if(rs != null)
 65.1210 +        rs.close();
 65.1211 +    }
 65.1212 +  }
 65.1213 +
 65.1214 +  /**
 65.1215 +   * Checks if there is an article with the given messageid in the Database.
 65.1216 +   * @param name
 65.1217 +   * @return
 65.1218 +   * @throws java.sql.SQLException
 65.1219 +   */
 65.1220 +  public boolean isArticleExisting(String messageID)
 65.1221 +    throws SQLException
 65.1222 +  {
 65.1223 +    ResultSet rs = null;
 65.1224 +    
 65.1225 +    try
 65.1226 +    {
 65.1227 +      this.pstmtIsArticleExisting.setString(1, messageID);
 65.1228 +      rs = this.pstmtIsArticleExisting.executeQuery();
 65.1229 +      return rs.next() && rs.getInt(1) == 1;
 65.1230 +    }
 65.1231 +    catch(SQLException ex)
 65.1232 +    {
 65.1233 +      restartConnection(ex);
 65.1234 +      return isArticleExisting(messageID);
 65.1235 +    }
 65.1236 +    finally
 65.1237 +    {
 65.1238 +      if(rs != null)
 65.1239 +        rs.close();
 65.1240 +    }
 65.1241 +  }
 65.1242 +  
 65.1243 +  /**
 65.1244 +   * Checks if there is a group with the given name in the Database.
 65.1245 +   * @param name
 65.1246 +   * @return
 65.1247 +   * @throws java.sql.SQLException
 65.1248 +   */
 65.1249 +  public boolean isGroupExisting(String name)
 65.1250 +    throws SQLException
 65.1251 +  {
 65.1252 +    ResultSet rs = null;
 65.1253 +    
 65.1254 +    try
 65.1255 +    {
 65.1256 +      this.pstmtIsGroupExisting.setString(1, name);
 65.1257 +      rs = this.pstmtIsGroupExisting.executeQuery();
 65.1258 +      return rs.next();
 65.1259 +    }
 65.1260 +    catch(SQLException ex)
 65.1261 +    {
 65.1262 +      restartConnection(ex);
 65.1263 +      return isGroupExisting(name);
 65.1264 +    }
 65.1265 +    finally
 65.1266 +    {
 65.1267 +      if(rs != null)
 65.1268 +        rs.close();
 65.1269 +    }
 65.1270 +  }
 65.1271 +  
 65.1272 +  public void setConfigValue(String key, String value)
 65.1273 +    throws SQLException
 65.1274 +  {
 65.1275 +    try
 65.1276 +    {
 65.1277 +      conn.setAutoCommit(false);
 65.1278 +      this.pstmtSetConfigValue0.setString(1, key);
 65.1279 +      this.pstmtSetConfigValue0.execute();
 65.1280 +      this.pstmtSetConfigValue1.setString(1, key);
 65.1281 +      this.pstmtSetConfigValue1.setString(2, value);
 65.1282 +      this.pstmtSetConfigValue1.execute();
 65.1283 +      conn.commit();
 65.1284 +      conn.setAutoCommit(true);
 65.1285 +    }
 65.1286 +    catch(SQLException ex)
 65.1287 +    {
 65.1288 +      restartConnection(ex);
 65.1289 +      setConfigValue(key, value);
 65.1290 +    }
 65.1291 +  }
 65.1292 +  
 65.1293 +  /**
 65.1294 +   * Closes the Database connection.
 65.1295 +   */
 65.1296 +  public void shutdown()
 65.1297 +    throws SQLException
 65.1298 +  {
 65.1299 +    if(this.conn != null)
 65.1300 +    {
 65.1301 +      this.conn.close();
 65.1302 +    }
 65.1303 +  }
 65.1304 +  
 65.1305 +  private void restartConnection(SQLException cause)
 65.1306 +    throws SQLException
 65.1307 +  {
 65.1308 +    restarts++;
 65.1309 +    Log.msg(Thread.currentThread() 
 65.1310 +      + ": Database connection was closed (restart " + restarts + ").", false);
 65.1311 +    
 65.1312 +    if(restarts >= MAX_RESTARTS)
 65.1313 +    {
 65.1314 +      // Delete the current, probably broken Database instance.
 65.1315 +      // So no one can use the instance any more.
 65.1316 +      Database.instances.remove(Thread.currentThread());
 65.1317 +      
 65.1318 +      // Throw the exception upwards
 65.1319 +      throw cause;
 65.1320 +    }
 65.1321 +    
 65.1322 +    try
 65.1323 +    {
 65.1324 +      Thread.sleep(1500L * restarts);
 65.1325 +    }
 65.1326 +    catch(InterruptedException ex)
 65.1327 +    {
 65.1328 +      Log.msg("Interrupted: " + ex.getMessage(), false);
 65.1329 +    }
 65.1330 +    
 65.1331 +    // Try to properly close the old database connection
 65.1332 +    try
 65.1333 +    {
 65.1334 +      if(this.conn != null)
 65.1335 +      {
 65.1336 +        this.conn.close();
 65.1337 +      }
 65.1338 +    }
 65.1339 +    catch(SQLException ex)
 65.1340 +    {
 65.1341 +      Log.msg(ex.getMessage(), true);
 65.1342 +    }
 65.1343 +    
 65.1344 +    try
 65.1345 +    {
 65.1346 +      // Try to reinitialize database connection
 65.1347 +      arise();
 65.1348 +    }
 65.1349 +    catch(SQLException ex)
 65.1350 +    {
 65.1351 +      Log.msg(ex.getMessage(), true);
 65.1352 +      restartConnection(ex);
 65.1353 +    }
 65.1354 +  }
 65.1355 +
 65.1356 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/org/sonews/daemon/storage/Group.java	Fri Jun 26 16:48:50 2009 +0200
    66.3 @@ -0,0 +1,186 @@
    66.4 +/*
    66.5 + *   SONEWS News Server
    66.6 + *   see AUTHORS for the list of contributors
    66.7 + *
    66.8 + *   This program is free software: you can redistribute it and/or modify
    66.9 + *   it under the terms of the GNU General Public License as published by
   66.10 + *   the Free Software Foundation, either version 3 of the License, or
   66.11 + *   (at your option) any later version.
   66.12 + *
   66.13 + *   This program is distributed in the hope that it will be useful,
   66.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   66.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   66.16 + *   GNU General Public License for more details.
   66.17 + *
   66.18 + *   You should have received a copy of the GNU General Public License
   66.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   66.20 + */
   66.21 +
   66.22 +package org.sonews.daemon.storage;
   66.23 +
   66.24 +import java.sql.SQLException;
   66.25 +import java.util.List;
   66.26 +import org.sonews.util.Log;
   66.27 +import org.sonews.util.Pair;
   66.28 +
   66.29 +/**
   66.30 + * Represents a logical Group within this newsserver.
   66.31 + * @author Christian Lins
   66.32 + * @since sonews/0.5.0
   66.33 + */
   66.34 +public class Group
   66.35 +{
   66.36 +
   66.37 +  /** 
   66.38 +   * If this flag is set the Group is no real newsgroup but a mailing list
   66.39 +   * mirror. In that case every posting and receiving mails must go through
   66.40 +   * the mailing list gateway.
   66.41 +   */
   66.42 +  public static final int MAILINGLIST = 0x1;
   66.43 +  
   66.44 +  /**
   66.45 +   * If this flag is set the Group is marked as readonly and the posting
   66.46 +   * is prohibited. This can be useful for groups that are synced only in
   66.47 +   * one direction.
   66.48 +   */
   66.49 +  public static final int READONLY    = 0x2;
   66.50 +
   66.51 +  /**
   66.52 +   * If this flag is set the Group is marked as deleted and must not occur
   66.53 +   * in any output. The deletion is done lazily by a low priority daemon.
   66.54 +   */
   66.55 +  public static final int DELETED     = 0x128;
   66.56 +  
   66.57 +  private long   id     = 0;
   66.58 +  private int    flags  = -1;
   66.59 +  private String name   = null;
   66.60 +  
   66.61 +  /**
   66.62 +   * Returns a Group identified by its full name.
   66.63 +   * @param name
   66.64 +   * @return
   66.65 +   */
   66.66 +  public static Group getByName(final String name)
   66.67 +  {
   66.68 +    try
   66.69 +    {
   66.70 +      return Database.getInstance().getGroup(name);
   66.71 +    }
   66.72 +    catch(SQLException ex)
   66.73 +    {
   66.74 +      ex.printStackTrace();
   66.75 +      return null;
   66.76 +    }
   66.77 +  }
   66.78 +
   66.79 +  /**
   66.80 +   * @return List of all groups this server handles.
   66.81 +   */
   66.82 +  public static List<Group> getAll()
   66.83 +  {
   66.84 +    try
   66.85 +    {
   66.86 +      return Database.getInstance().getGroups();
   66.87 +    }
   66.88 +    catch(SQLException ex)
   66.89 +    {
   66.90 +      Log.msg(ex.getMessage(), false);
   66.91 +      return null;
   66.92 +    }
   66.93 +  }
   66.94 +  
   66.95 +  /**
   66.96 +   * Private constructor.
   66.97 +   * @param name
   66.98 +   * @param id
   66.99 +   */
  66.100 +  Group(final String name, final long id, final int flags)
  66.101 +  {
  66.102 +    this.id    = id;
  66.103 +    this.flags = flags;
  66.104 +    this.name  = name;
  66.105 +  }
  66.106 +
  66.107 +  @Override
  66.108 +  public boolean equals(Object obj)
  66.109 +  {
  66.110 +    if(obj instanceof Group)
  66.111 +    {
  66.112 +      return ((Group)obj).id == this.id;
  66.113 +    }
  66.114 +    else
  66.115 +    {
  66.116 +      return false;
  66.117 +    }
  66.118 +  }
  66.119 +    
  66.120 +  public List<Pair<Long, ArticleHead>> getArticleHeads(final int first, final int last)
  66.121 +    throws SQLException
  66.122 +  {
  66.123 +    return Database.getInstance().getArticleHeads(this, first, last);
  66.124 +  }
  66.125 +  
  66.126 +  public List<Long> getArticleNumbers()
  66.127 +    throws SQLException
  66.128 +  {
  66.129 +    return Database.getInstance().getArticleNumbers(id);
  66.130 +  }
  66.131 +
  66.132 +  public int getFirstArticleNumber()
  66.133 +    throws SQLException
  66.134 +  {
  66.135 +    return Database.getInstance().getFirstArticleNumber(this);
  66.136 +  }
  66.137 +
  66.138 +  /**
  66.139 +   * Returns the group id.
  66.140 +   */
  66.141 +  public long getID()
  66.142 +  {
  66.143 +    assert id > 0;
  66.144 +
  66.145 +    return id;
  66.146 +  }
  66.147 +  
  66.148 +  public boolean isMailingList()
  66.149 +  {
  66.150 +    return (this.flags & MAILINGLIST) != 0;
  66.151 +  }
  66.152 +
  66.153 +  public int getLastArticleNumber()
  66.154 +    throws SQLException
  66.155 +  {
  66.156 +    return Database.getInstance().getLastArticleNumber(this);
  66.157 +  }
  66.158 +
  66.159 +  public String getName()
  66.160 +  {
  66.161 +    return name;
  66.162 +  }
  66.163 +
  66.164 +  /**
  66.165 +   * Performs this.flags |= flag to set a specified flag and updates the data
  66.166 +   * in the Database.
  66.167 +   * @param flag
  66.168 +   */
  66.169 +  public void setFlag(final int flag)
  66.170 +  {
  66.171 +    this.flags |= flag;
  66.172 +  }
  66.173 +
  66.174 +  public void setName(final String name)
  66.175 +  {
  66.176 +    this.name = name;
  66.177 +  }
  66.178 +
  66.179 +  /**
  66.180 +   * @return Number of posted articles in this group.
  66.181 +   * @throws java.sql.SQLException
  66.182 +   */
  66.183 +  public int getPostingsCount()
  66.184 +    throws SQLException
  66.185 +  {
  66.186 +    return Database.getInstance().getPostingsCount(this.name);
  66.187 +  }
  66.188 +
  66.189 +}
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/org/sonews/daemon/storage/Headers.java	Fri Jun 26 16:48:50 2009 +0200
    67.3 @@ -0,0 +1,51 @@
    67.4 +/*
    67.5 + *   SONEWS News Server
    67.6 + *   see AUTHORS for the list of contributors
    67.7 + *
    67.8 + *   This program is free software: you can redistribute it and/or modify
    67.9 + *   it under the terms of the GNU General Public License as published by
   67.10 + *   the Free Software Foundation, either version 3 of the License, or
   67.11 + *   (at your option) any later version.
   67.12 + *
   67.13 + *   This program is distributed in the hope that it will be useful,
   67.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   67.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   67.16 + *   GNU General Public License for more details.
   67.17 + *
   67.18 + *   You should have received a copy of the GNU General Public License
   67.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   67.20 + */
   67.21 +
   67.22 +package org.sonews.daemon.storage;
   67.23 +
   67.24 +/**
   67.25 + * Contains header constants. These header keys are no way complete but all
   67.26 + * headers that are relevant for sonews.
   67.27 + * @author Christian Lins
   67.28 + * @since sonews/0.5.0
   67.29 + */
   67.30 +public final class Headers
   67.31 +{
   67.32 +
   67.33 +  public static final String BYTES             = "bytes";
   67.34 +  public static final String CONTENT_TYPE      = "content-type";
   67.35 +  public static final String CONTROL           = "control";
   67.36 +  public static final String DATE              = "date";
   67.37 +  public static final String FROM              = "from";
   67.38 +  public static final String LINES             = "lines";
   67.39 +  public static final String MESSAGE_ID        = "message-id";
   67.40 +  public static final String NEWSGROUPS        = "newsgroups";
   67.41 +  public static final String NNTP_POSTING_DATE = "nntp-posting-date";
   67.42 +  public static final String NNTP_POSTING_HOST = "nntp-posting-host";
   67.43 +  public static final String PATH              = "path";
   67.44 +  public static final String REFERENCES        = "references";
   67.45 +  public static final String SUBJECT           = "subject";
   67.46 +  public static final String SUPERSEDES        = "subersedes";
   67.47 +  public static final String X_COMPLAINTS_TO   = "x-complaints-to";
   67.48 +  public static final String X_TRACE           = "x-trace";
   67.49 +  public static final String XREF              = "xref";
   67.50 +
   67.51 +  private Headers()
   67.52 +  {}
   67.53 +
   67.54 +}
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/org/sonews/daemon/storage/package.html	Fri Jun 26 16:48:50 2009 +0200
    68.3 @@ -0,0 +1,2 @@
    68.4 +Contains classes of the storage backend and the Group and Article
    68.5 +abstraction.
    68.6 \ No newline at end of file
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/org/sonews/feed/AbstractFeeder.java	Fri Jun 26 16:48:50 2009 +0200
    69.3 @@ -0,0 +1,41 @@
    69.4 +/*
    69.5 + *   SONEWS News Server
    69.6 + *   see AUTHORS for the list of contributors
    69.7 + *
    69.8 + *   This program is free software: you can redistribute it and/or modify
    69.9 + *   it under the terms of the GNU General Public License as published by
   69.10 + *   the Free Software Foundation, either version 3 of the License, or
   69.11 + *   (at your option) any later version.
   69.12 + *
   69.13 + *   This program is distributed in the hope that it will be useful,
   69.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   69.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   69.16 + *   GNU General Public License for more details.
   69.17 + *
   69.18 + *   You should have received a copy of the GNU General Public License
   69.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   69.20 + */
   69.21 +
   69.22 +package org.sonews.feed;
   69.23 +
   69.24 +import java.util.ArrayList;
   69.25 +import java.util.List;
   69.26 +import org.sonews.daemon.AbstractDaemon;
   69.27 +
   69.28 +/**
   69.29 + * Base class for PullFeeder and PushFeeder.
   69.30 + * @author Christian Lins
   69.31 + * @since sonews/0.5.0
   69.32 + */
   69.33 +abstract class AbstractFeeder extends AbstractDaemon
   69.34 +{
   69.35 +
   69.36 +  /** List of subscriptions that is processed by this feeder */
   69.37 +  protected List<Subscription> subscriptions = new ArrayList<Subscription>();
   69.38 +  
   69.39 +  public void addSubscription(final Subscription sub)
   69.40 +  {
   69.41 +    this.subscriptions.add(sub);
   69.42 +  }
   69.43 +  
   69.44 +}
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/org/sonews/feed/FeedManager.java	Fri Jun 26 16:48:50 2009 +0200
    70.3 @@ -0,0 +1,71 @@
    70.4 +/*
    70.5 + *   SONEWS News Server
    70.6 + *   see AUTHORS for the list of contributors
    70.7 + *
    70.8 + *   This program is free software: you can redistribute it and/or modify
    70.9 + *   it under the terms of the GNU General Public License as published by
   70.10 + *   the Free Software Foundation, either version 3 of the License, or
   70.11 + *   (at your option) any later version.
   70.12 + *
   70.13 + *   This program is distributed in the hope that it will be useful,
   70.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   70.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   70.16 + *   GNU General Public License for more details.
   70.17 + *
   70.18 + *   You should have received a copy of the GNU General Public License
   70.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   70.20 + */
   70.21 +
   70.22 +package org.sonews.feed;
   70.23 +
   70.24 +import java.sql.SQLException;
   70.25 +import java.util.List;
   70.26 +import org.sonews.daemon.storage.Article;
   70.27 +import org.sonews.daemon.storage.Database;
   70.28 +
   70.29 +/**
   70.30 + * Controlls push and pull feeder.
   70.31 + * @author Christian Lins
   70.32 + * @since sonews/0.5.0
   70.33 + */
   70.34 +public final class FeedManager 
   70.35 +{
   70.36 +
   70.37 +  public static final int TYPE_PULL = 0;
   70.38 +  public static final int TYPE_PUSH = 1;
   70.39 +  
   70.40 +  private static PullFeeder pullFeeder = new PullFeeder();
   70.41 +  private static PushFeeder pushFeeder = new PushFeeder();
   70.42 +  
   70.43 +  /**
   70.44 +   * Reads the peer subscriptions from database and starts the appropriate
   70.45 +   * PullFeeder or PushFeeder.
   70.46 +   */
   70.47 +  public static synchronized void startFeeding()
   70.48 +    throws SQLException
   70.49 +  {
   70.50 +    List<Subscription> subsPull = Database.getInstance()
   70.51 +      .getSubscriptions(TYPE_PULL);
   70.52 +    for(Subscription sub : subsPull)
   70.53 +    {
   70.54 +      pullFeeder.addSubscription(sub);
   70.55 +    }
   70.56 +    pullFeeder.start();
   70.57 +    
   70.58 +    List<Subscription> subsPush = Database.getInstance()
   70.59 +      .getSubscriptions(TYPE_PUSH);
   70.60 +    for(Subscription sub : subsPush)
   70.61 +    {
   70.62 +      pushFeeder.addSubscription(sub);
   70.63 +    }
   70.64 +    pushFeeder.start();
   70.65 +  }
   70.66 +  
   70.67 +  public static void queueForPush(Article article)
   70.68 +  {
   70.69 +    pushFeeder.queueForPush(article);
   70.70 +  }
   70.71 +  
   70.72 +  private FeedManager() {}
   70.73 +  
   70.74 +}
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/org/sonews/feed/PullFeeder.java	Fri Jun 26 16:48:50 2009 +0200
    71.3 @@ -0,0 +1,250 @@
    71.4 +/*
    71.5 + *   SONEWS News Server
    71.6 + *   see AUTHORS for the list of contributors
    71.7 + *
    71.8 + *   This program is free software: you can redistribute it and/or modify
    71.9 + *   it under the terms of the GNU General Public License as published by
   71.10 + *   the Free Software Foundation, either version 3 of the License, or
   71.11 + *   (at your option) any later version.
   71.12 + *
   71.13 + *   This program is distributed in the hope that it will be useful,
   71.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   71.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   71.16 + *   GNU General Public License for more details.
   71.17 + *
   71.18 + *   You should have received a copy of the GNU General Public License
   71.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   71.20 + */
   71.21 +
   71.22 +package org.sonews.feed;
   71.23 +
   71.24 +import java.io.BufferedReader;
   71.25 +import java.io.IOException;
   71.26 +import java.io.InputStreamReader;
   71.27 +import java.io.PrintWriter;
   71.28 +import java.net.Socket;
   71.29 +import java.net.SocketException;
   71.30 +import java.net.UnknownHostException;
   71.31 +import java.sql.SQLException;
   71.32 +import java.util.ArrayList;
   71.33 +import java.util.HashMap;
   71.34 +import java.util.List;
   71.35 +import java.util.Map;
   71.36 +import org.sonews.daemon.Config;
   71.37 +import org.sonews.util.Log;
   71.38 +import org.sonews.daemon.storage.Database;
   71.39 +import org.sonews.util.Stats;
   71.40 +import org.sonews.util.io.ArticleReader;
   71.41 +import org.sonews.util.io.ArticleWriter;
   71.42 +
   71.43 +/**
   71.44 + * The PullFeeder class regularily checks another Newsserver for new
   71.45 + * messages.
   71.46 + * @author Christian Lins
   71.47 + * @since sonews/0.5.0
   71.48 + */
   71.49 +class PullFeeder extends AbstractFeeder
   71.50 +{
   71.51 +  
   71.52 +  private Map<Subscription, Integer> highMarks = new HashMap<Subscription, Integer>();
   71.53 +  private BufferedReader             in;
   71.54 +  private PrintWriter                out;
   71.55 +  
   71.56 +  @Override
   71.57 +  public void addSubscription(final Subscription sub)
   71.58 +  {
   71.59 +    super.addSubscription(sub);
   71.60 +    
   71.61 +    // Set a initial highMark
   71.62 +    this.highMarks.put(sub, 0);
   71.63 +  }
   71.64 +  
   71.65 +  /**
   71.66 +   * Changes to the given group and returns its high mark.
   71.67 +   * @param groupName
   71.68 +   * @return
   71.69 +   */
   71.70 +  private int changeGroup(String groupName)
   71.71 +    throws IOException
   71.72 +  {
   71.73 +    this.out.print("GROUP " + groupName + "\r\n");
   71.74 +    this.out.flush();
   71.75 +    
   71.76 +    String line = this.in.readLine();
   71.77 +    if(line.startsWith("211 "))
   71.78 +    {
   71.79 +      int highmark = Integer.parseInt(line.split(" ")[3]);
   71.80 +      return highmark;
   71.81 +    }
   71.82 +    else
   71.83 +    {
   71.84 +      throw new IOException("GROUP " + groupName + " returned: " + line);
   71.85 +    }
   71.86 +  }
   71.87 +  
   71.88 +  private void connectTo(final String host, final int port)
   71.89 +    throws IOException, UnknownHostException
   71.90 +  {
   71.91 +    Socket socket = new Socket(host, port);
   71.92 +    this.out = new PrintWriter(socket.getOutputStream());
   71.93 +    this.in  = new BufferedReader(new InputStreamReader(socket.getInputStream()));
   71.94 +
   71.95 +    String line = in.readLine();
   71.96 +    if(!(line.charAt(0) == '2')) // Could be 200 or 2xx if posting is not allowed
   71.97 +    {
   71.98 +      throw new IOException(line);
   71.99 +    }
  71.100 +  }
  71.101 +  
  71.102 +  private void disconnect()
  71.103 +    throws IOException
  71.104 +  {
  71.105 +    this.out.print("QUIT\r\n");
  71.106 +    this.out.flush();
  71.107 +    this.out.close();
  71.108 +    this.in.close();
  71.109 +    
  71.110 +    this.out = null;
  71.111 +    this.in  = null;
  71.112 +  }
  71.113 +  
  71.114 +  /**
  71.115 +   * Uses the OVER or XOVER command to get a list of message overviews that
  71.116 +   * may be unknown to this feeder and are about to be peered.
  71.117 +   * @param start
  71.118 +   * @param end
  71.119 +   * @return A list of message ids with potentially interesting messages.
  71.120 +   */
  71.121 +  private List<String> over(int start, int end)
  71.122 +    throws IOException
  71.123 +  {
  71.124 +    this.out.print("OVER " + start + "-" + end + "\r\n");
  71.125 +    this.out.flush();
  71.126 +    
  71.127 +    String line = this.in.readLine();
  71.128 +    if(line.startsWith("500 ")) // OVER not supported
  71.129 +    {
  71.130 +      this.out.print("XOVER " + start + "-" + end + "\r\n");
  71.131 +      this.out.flush();
  71.132 +      
  71.133 +      line = this.in.readLine();
  71.134 +    }
  71.135 +    
  71.136 +    if(line.startsWith("224 "))
  71.137 +    {
  71.138 +      List<String> messages = new ArrayList<String>();
  71.139 +      line = this.in.readLine();
  71.140 +      while(!".".equals(line))
  71.141 +      {
  71.142 +        String mid = line.split("\t")[4]; // 5th should be the Message-ID
  71.143 +        messages.add(mid);
  71.144 +        line = this.in.readLine();
  71.145 +      }
  71.146 +      return messages;
  71.147 +    }
  71.148 +    else
  71.149 +    {
  71.150 +      throw new IOException("Server return for OVER/XOVER: " + line);
  71.151 +    }
  71.152 +  }
  71.153 +  
  71.154 +  @Override
  71.155 +  public void run()
  71.156 +  {
  71.157 +    while(isRunning())
  71.158 +    {
  71.159 +      int pullInterval = 1000 * 
  71.160 +        Config.getInstance().get(Config.FEED_PULLINTERVAL, 3600);
  71.161 +      String host = "localhost";
  71.162 +      int    port = 119;
  71.163 +      
  71.164 +      Log.msg("Start PullFeeder run...", true);
  71.165 +
  71.166 +      try
  71.167 +      {
  71.168 +        for(Subscription sub : this.subscriptions)
  71.169 +        {
  71.170 +          host = sub.getHost();
  71.171 +          port = sub.getPort();
  71.172 +
  71.173 +          try
  71.174 +          {
  71.175 +            Log.msg("Feeding " + sub.getGroup() + " from " + sub.getHost(), true);
  71.176 +            try
  71.177 +            {
  71.178 +              connectTo(host, port);
  71.179 +            }
  71.180 +            catch(SocketException ex)
  71.181 +            {
  71.182 +              Log.msg("Skipping " + sub.getHost() + ": " + ex, false);
  71.183 +              continue;
  71.184 +            }
  71.185 +            
  71.186 +            int oldMark = this.highMarks.get(sub);
  71.187 +            int newMark = changeGroup(sub.getGroup());
  71.188 +            
  71.189 +            if(oldMark != newMark)
  71.190 +            {
  71.191 +              List<String> messageIDs = over(oldMark, newMark);
  71.192 +
  71.193 +              for(String messageID : messageIDs)
  71.194 +              {
  71.195 +                if(Database.getInstance().isArticleExisting(messageID))
  71.196 +                {
  71.197 +                  continue;
  71.198 +                }
  71.199 +
  71.200 +                try
  71.201 +                {
  71.202 +                  // Post the message via common socket connection
  71.203 +                  ArticleReader aread =
  71.204 +                    new ArticleReader(sub.getHost(), sub.getPort(), messageID);
  71.205 +                  byte[] abuf = aread.getArticleData();
  71.206 +                  if (abuf == null)
  71.207 +                  {
  71.208 +                    Log.msg("Could not feed " + messageID + " from " + sub.getHost(), true);
  71.209 +                  }
  71.210 +                  else
  71.211 +                  {
  71.212 +                    Log.msg("Feeding " + messageID, true);
  71.213 +                    ArticleWriter awrite = new ArticleWriter(
  71.214 +                      "localhost", Config.getInstance().get(Config.PORT, 119));
  71.215 +                    awrite.writeArticle(abuf);
  71.216 +                    awrite.close();
  71.217 +                  }
  71.218 +                  Stats.getInstance().mailFeeded(sub.getGroup());
  71.219 +                }
  71.220 +                catch(IOException ex)
  71.221 +                {
  71.222 +                  // There may be a temporary network failure
  71.223 +                  ex.printStackTrace();
  71.224 +                  Log.msg("Skipping mail " + messageID + " due to exception.", false);
  71.225 +                }
  71.226 +              } // for(;;)
  71.227 +              this.highMarks.put(sub, newMark);
  71.228 +            }
  71.229 +            
  71.230 +            disconnect();
  71.231 +          }
  71.232 +          catch(SQLException ex)
  71.233 +          {
  71.234 +            ex.printStackTrace();
  71.235 +          }
  71.236 +          catch(IOException ex)
  71.237 +          {
  71.238 +            ex.printStackTrace();
  71.239 +            Log.msg("PullFeeder run stopped due to exception.", false);
  71.240 +          }
  71.241 +        } // for(Subscription sub : subscriptions)
  71.242 +        
  71.243 +        Log.msg("PullFeeder run ended. Waiting " + pullInterval / 1000 + "s", true);
  71.244 +        Thread.sleep(pullInterval);
  71.245 +      }
  71.246 +      catch(InterruptedException ex)
  71.247 +      {
  71.248 +        Log.msg(ex.getMessage(), false);
  71.249 +      }
  71.250 +    }
  71.251 +  }
  71.252 +  
  71.253 +}
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/org/sonews/feed/PushFeeder.java	Fri Jun 26 16:48:50 2009 +0200
    72.3 @@ -0,0 +1,107 @@
    72.4 +/*
    72.5 + *   SONEWS News Server
    72.6 + *   see AUTHORS for the list of contributors
    72.7 + *
    72.8 + *   This program is free software: you can redistribute it and/or modify
    72.9 + *   it under the terms of the GNU General Public License as published by
   72.10 + *   the Free Software Foundation, either version 3 of the License, or
   72.11 + *   (at your option) any later version.
   72.12 + *
   72.13 + *   This program is distributed in the hope that it will be useful,
   72.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   72.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   72.16 + *   GNU General Public License for more details.
   72.17 + *
   72.18 + *   You should have received a copy of the GNU General Public License
   72.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   72.20 + */
   72.21 +
   72.22 +package org.sonews.feed;
   72.23 +
   72.24 +import java.io.IOException;
   72.25 +import java.util.concurrent.ConcurrentLinkedQueue;
   72.26 +import org.sonews.daemon.storage.Article;
   72.27 +import org.sonews.daemon.storage.Headers;
   72.28 +import org.sonews.util.Log;
   72.29 +import org.sonews.util.io.ArticleWriter;
   72.30 +
   72.31 +/**
   72.32 + * Pushes new articles to remote newsservers. This feeder sleeps until a new
   72.33 + * message is posted to the sonews instance.
   72.34 + * @author Christian Lins
   72.35 + * @since sonews/0.5.0
   72.36 + */
   72.37 +class PushFeeder extends AbstractFeeder
   72.38 +{
   72.39 +  
   72.40 +  private ConcurrentLinkedQueue<Article> articleQueue = 
   72.41 +    new ConcurrentLinkedQueue<Article>();
   72.42 +  
   72.43 +  @Override
   72.44 +  public void run()
   72.45 +  {
   72.46 +    while(isRunning())
   72.47 +    {
   72.48 +      try
   72.49 +      {
   72.50 +        synchronized(this)
   72.51 +        {
   72.52 +          this.wait();
   72.53 +        }
   72.54 +        
   72.55 +        Article  article = this.articleQueue.poll();
   72.56 +        String[] groups  = article.getHeader(Headers.NEWSGROUPS)[0].split(",");
   72.57 +        Log.msg("PushFeed: " + article.getMessageID(), true);
   72.58 +        for(Subscription sub : this.subscriptions)
   72.59 +        {
   72.60 +          // Circle check
   72.61 +          if(article.getHeader(Headers.PATH)[0].contains(sub.getHost()))
   72.62 +          {
   72.63 +            Log.msg(article.getMessageID() + " skipped for host " 
   72.64 +              + sub.getHost(), true);
   72.65 +            continue;
   72.66 +          }
   72.67 +
   72.68 +          try
   72.69 +          {
   72.70 +            for(String group : groups)
   72.71 +            {
   72.72 +              if(sub.getGroup().equals(group))
   72.73 +              {
   72.74 +                // Delete headers that may cause problems
   72.75 +                article.removeHeader(Headers.NNTP_POSTING_DATE);
   72.76 +                article.removeHeader(Headers.NNTP_POSTING_HOST);
   72.77 +                article.removeHeader(Headers.X_COMPLAINTS_TO);
   72.78 +                article.removeHeader(Headers.X_TRACE);
   72.79 +                article.removeHeader(Headers.XREF);
   72.80 +                
   72.81 +                // POST the message to remote server
   72.82 +                ArticleWriter awriter = new ArticleWriter(sub.getHost(), sub.getPort());
   72.83 +                awriter.writeArticle(article);
   72.84 +                break;
   72.85 +              }
   72.86 +            }
   72.87 +          }
   72.88 +          catch(IOException ex)
   72.89 +          {
   72.90 +            Log.msg(ex, false);
   72.91 +          }
   72.92 +        }
   72.93 +      }
   72.94 +      catch(InterruptedException ex)
   72.95 +      {
   72.96 +        Log.msg("PushFeeder interrupted.", true);
   72.97 +      }
   72.98 +    }
   72.99 +  }
  72.100 +  
  72.101 +  public void queueForPush(Article article)
  72.102 +  {
  72.103 +    this.articleQueue.add(article);
  72.104 +    synchronized(this)
  72.105 +    {
  72.106 +      this.notifyAll();
  72.107 +    }
  72.108 +  }
  72.109 +  
  72.110 +}
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/org/sonews/feed/Subscription.java	Fri Jun 26 16:48:50 2009 +0200
    73.3 @@ -0,0 +1,63 @@
    73.4 +/*
    73.5 + *   SONEWS News Server
    73.6 + *   see AUTHORS for the list of contributors
    73.7 + *
    73.8 + *   This program is free software: you can redistribute it and/or modify
    73.9 + *   it under the terms of the GNU General Public License as published by
   73.10 + *   the Free Software Foundation, either version 3 of the License, or
   73.11 + *   (at your option) any later version.
   73.12 + *
   73.13 + *   This program is distributed in the hope that it will be useful,
   73.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   73.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   73.16 + *   GNU General Public License for more details.
   73.17 + *
   73.18 + *   You should have received a copy of the GNU General Public License
   73.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   73.20 + */
   73.21 +
   73.22 +package org.sonews.feed;
   73.23 +
   73.24 +/**
   73.25 + * For every group that is synchronized with or from a remote newsserver 
   73.26 + * a Subscription instance exists.
   73.27 + * @author Christian Lins
   73.28 + * @since sonews/0.5.0
   73.29 + */
   73.30 +public class Subscription 
   73.31 +{
   73.32 +
   73.33 +  private String host;
   73.34 +  private int    port;
   73.35 +  private int    feedtype;
   73.36 +  private String group;
   73.37 +  
   73.38 +  public Subscription(String host, int port, int feedtype, String group)
   73.39 +  {
   73.40 +    this.host     = host;
   73.41 +    this.port     = port;
   73.42 +    this.feedtype = feedtype;
   73.43 +    this.group    = group;
   73.44 +  }
   73.45 +
   73.46 +  public int getFeedtype()
   73.47 +  {
   73.48 +    return feedtype;
   73.49 +  }
   73.50 +
   73.51 +  public String getGroup()
   73.52 +  {
   73.53 +    return group;
   73.54 +  }
   73.55 +
   73.56 +  public String getHost()
   73.57 +  {
   73.58 +    return host;
   73.59 +  }
   73.60 +
   73.61 +  public int getPort()
   73.62 +  {
   73.63 +    return port;
   73.64 +  }
   73.65 +  
   73.66 +}
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/org/sonews/feed/package.html	Fri Jun 26 16:48:50 2009 +0200
    74.3 @@ -0,0 +1,2 @@
    74.4 +Contains classes for the peering functionality, e.g. pulling and pushing
    74.5 +mails from and to remote newsservers.
    74.6 \ No newline at end of file
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/org/sonews/mlgw/Dispatcher.java	Fri Jun 26 16:48:50 2009 +0200
    75.3 @@ -0,0 +1,251 @@
    75.4 +/*
    75.5 + *   SONEWS News Server
    75.6 + *   see AUTHORS for the list of contributors
    75.7 + *
    75.8 + *   This program is free software: you can redistribute it and/or modify
    75.9 + *   it under the terms of the GNU General Public License as published by
   75.10 + *   the Free Software Foundation, either version 3 of the License, or
   75.11 + *   (at your option) any later version.
   75.12 + *
   75.13 + *   This program is distributed in the hope that it will be useful,
   75.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   75.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   75.16 + *   GNU General Public License for more details.
   75.17 + *
   75.18 + *   You should have received a copy of the GNU General Public License
   75.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   75.20 + */
   75.21 +
   75.22 +package org.sonews.mlgw;
   75.23 +
   75.24 +import java.io.IOException;
   75.25 +import org.sonews.daemon.Config;
   75.26 +import org.sonews.daemon.storage.Article;
   75.27 +import org.sonews.util.io.ArticleInputStream;
   75.28 +import org.sonews.daemon.storage.Database;
   75.29 +import java.sql.SQLException;
   75.30 +import java.util.ArrayList;
   75.31 +import java.util.List;
   75.32 +import java.util.Properties;
   75.33 +import javax.mail.Address;
   75.34 +import javax.mail.Authenticator;
   75.35 +import javax.mail.Message;
   75.36 +import javax.mail.MessagingException;
   75.37 +import javax.mail.PasswordAuthentication;
   75.38 +import javax.mail.Session;
   75.39 +import javax.mail.Transport;
   75.40 +import javax.mail.internet.InternetAddress;
   75.41 +import javax.mail.internet.MimeMessage;
   75.42 +import org.sonews.daemon.storage.Headers;
   75.43 +import org.sonews.util.Log;
   75.44 +import org.sonews.util.Stats;
   75.45 +
   75.46 +/**
   75.47 + * Dispatches messages from mailing list or newsserver or vice versa.
   75.48 + * @author Christian Lins
   75.49 + * @since sonews/0.5.0
   75.50 + */
   75.51 +public class Dispatcher 
   75.52 +{
   75.53 +
   75.54 +  static class PasswordAuthenticator extends Authenticator
   75.55 +  {
   75.56 +    
   75.57 +    @Override
   75.58 +    public PasswordAuthentication getPasswordAuthentication()
   75.59 +    {
   75.60 +      final String username = 
   75.61 +        Config.getInstance().get(Config.MLSEND_USER, "user");
   75.62 +      final String password = 
   75.63 +        Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
   75.64 +
   75.65 +      return new PasswordAuthentication(username, password);
   75.66 +    }
   75.67 +    
   75.68 +  }
   75.69 +  
   75.70 +  /**
   75.71 +   * Posts a message that was received from a mailing list to the 
   75.72 +   * appropriate newsgroup.
   75.73 +   * @param msg
   75.74 +   */
   75.75 +  public static boolean toGroup(final Message msg)
   75.76 +  {
   75.77 +    try
   75.78 +    {
   75.79 +      Address[] to = msg.getAllRecipients(); // includes TO/CC/BCC
   75.80 +      if(to == null || to.length <= 0)
   75.81 +      {
   75.82 +        Log.msg("Skipping message because no receipient!", true);
   75.83 +        return false;
   75.84 +      }
   75.85 +      else
   75.86 +      {
   75.87 +        boolean posted = false;
   75.88 +        for(Address toa : to) // Address can have '<' '>' around
   75.89 +        {
   75.90 +          if(!(toa instanceof InternetAddress))
   75.91 +          {
   75.92 +            continue;
   75.93 +          }
   75.94 +          String group = Database.getInstance()
   75.95 +            .getGroupForList((InternetAddress)toa);
   75.96 +          if(group != null)
   75.97 +          {
   75.98 +            Log.msg("Posting to group " + group, true);
   75.99 +
  75.100 +            // Create new Article object
  75.101 +            Article article = new Article(msg);
  75.102 +            article.setGroup(group);
  75.103 +            
  75.104 +            // Write article to database
  75.105 +            if(!Database.getInstance().isArticleExisting(article.getMessageID()))
  75.106 +            {
  75.107 +              Database.getInstance().addArticle(article);
  75.108 +              Stats.getInstance().mailGatewayed(
  75.109 +                article.getHeader(Headers.NEWSGROUPS)[0]);
  75.110 +            }
  75.111 +            else
  75.112 +            {
  75.113 +              Log.msg("Article " + article.getMessageID() + " already existing.", true);
  75.114 +              // TODO: It may be possible that a ML mail is posted to several
  75.115 +              // ML addresses...
  75.116 +            }
  75.117 +            posted = true;
  75.118 +          }
  75.119 +          else
  75.120 +          {
  75.121 +            Log.msg("No group for " + toa, true);
  75.122 +          }
  75.123 +        } // end for
  75.124 +        return posted;
  75.125 +      }
  75.126 +    }
  75.127 +    catch(Exception ex)
  75.128 +    {
  75.129 +      ex.printStackTrace();
  75.130 +      return false;
  75.131 +    }
  75.132 +  }
  75.133 +  
  75.134 +  /**
  75.135 +   * Mails a message received through NNTP to the appropriate mailing list.
  75.136 +   */
  75.137 +  public static void toList(Article article)
  75.138 +    throws IOException, MessagingException, SQLException
  75.139 +  {
  75.140 +    // Get mailing lists for the group of this article
  75.141 +    List<String> listAddresses = new ArrayList<String>();
  75.142 +    String[]     groupnames    = article.getHeader(Headers.NEWSGROUPS)[0].split(",");
  75.143 +    
  75.144 +    for(String groupname : groupnames)
  75.145 +    {
  75.146 +      String listAddress = Database.getInstance().getListForGroup(groupname);
  75.147 +      if(listAddress != null)
  75.148 +      {
  75.149 +        listAddresses.add(listAddress);
  75.150 +      }
  75.151 +    }
  75.152 +
  75.153 +    for(String listAddress : listAddresses)
  75.154 +    {
  75.155 +      // Compose message and send it via given SMTP-Host
  75.156 +      String smtpHost = Config.getInstance().get(Config.MLSEND_HOST, "localhost");
  75.157 +      int    smtpPort = Config.getInstance().get(Config.MLSEND_PORT, 25);
  75.158 +      String smtpUser = Config.getInstance().get(Config.MLSEND_USER, "user");
  75.159 +      String smtpPw   = Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
  75.160 +
  75.161 +      Properties props    = System.getProperties();
  75.162 +      props.put("mail.smtp.localhost", 
  75.163 +        Config.getInstance().get(Config.HOSTNAME, "localhost"));
  75.164 +      props.put("mail.smtp.from",  // Used for MAIL FROM command
  75.165 +        Config.getInstance().get(
  75.166 +          Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]));
  75.167 +      props.put("mail.smtp.host", smtpHost);
  75.168 +      props.put("mail.smtp.port", smtpPort);
  75.169 +      props.put("mail.smtp.auth", "true");
  75.170 +
  75.171 +      Address[] address = new Address[1];
  75.172 +      address[0] = new InternetAddress(listAddress);
  75.173 +
  75.174 +      ArticleInputStream in = new ArticleInputStream(article);
  75.175 +      Session session = Session.getDefaultInstance(props, new PasswordAuthenticator());
  75.176 +      MimeMessage msg = new MimeMessage(session, in);
  75.177 +      msg.setRecipient(Message.RecipientType.TO, address[0]);
  75.178 +      msg.setReplyTo(address);
  75.179 +      msg.removeHeader(Headers.NEWSGROUPS);
  75.180 +      msg.removeHeader(Headers.PATH);
  75.181 +      msg.removeHeader(Headers.LINES);
  75.182 +      msg.removeHeader(Headers.BYTES);
  75.183 +      
  75.184 +      if(Config.getInstance().get(Config.MLSEND_RW_SENDER, false))
  75.185 +      {
  75.186 +        rewriteSenderAddress(msg); // Set the SENDER address
  75.187 +      }
  75.188 +      
  75.189 +      if(Config.getInstance().get(Config.MLSEND_RW_FROM, false))
  75.190 +      {
  75.191 +        rewriteFromAddress(msg);   // Set the FROM address
  75.192 +      }
  75.193 +      
  75.194 +      msg.saveChanges();
  75.195 +
  75.196 +      // Send the mail
  75.197 +      Transport transport = session.getTransport("smtp");
  75.198 +      transport.connect(smtpHost, smtpPort, smtpUser, smtpPw);
  75.199 +      transport.sendMessage(msg, msg.getAllRecipients());
  75.200 +      transport.close();
  75.201 +
  75.202 +      Stats.getInstance().mailGatewayed(article.getHeader(Headers.NEWSGROUPS)[0]);
  75.203 +      Log.msg("MLGateway: Mail " + article.getHeader("Subject")[0] 
  75.204 +        + " was delivered to " + listAddress + ".", true);
  75.205 +    }
  75.206 +  }
  75.207 +  
  75.208 +  /**
  75.209 +   * Sets the SENDER header of the given MimeMessage. This might be necessary
  75.210 +   * for moderated groups that does not allow the "normal" FROM sender.
  75.211 +   * @param msg
  75.212 +   * @throws javax.mail.MessagingException
  75.213 +   */
  75.214 +  private static void rewriteSenderAddress(MimeMessage msg)
  75.215 +    throws MessagingException
  75.216 +  {
  75.217 +    String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
  75.218 +
  75.219 +    if(mlAddress != null)
  75.220 +    {
  75.221 +      msg.setSender(new InternetAddress(mlAddress));
  75.222 +    }
  75.223 +    else
  75.224 +    {
  75.225 +      throw new MessagingException("Cannot rewrite SENDER header!");
  75.226 +    }
  75.227 +  }
  75.228 +  
  75.229 +  /**
  75.230 +   * Sets the FROM header of the given MimeMessage. This might be necessary
  75.231 +   * for moderated groups that does not allow the "normal" FROM sender.
  75.232 +   * @param msg
  75.233 +   * @throws javax.mail.MessagingException
  75.234 +   */
  75.235 +  private static void rewriteFromAddress(MimeMessage msg)
  75.236 +    throws MessagingException
  75.237 +  {
  75.238 +    Address[] froms  = msg.getFrom();
  75.239 +    String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
  75.240 +
  75.241 +    if(froms.length > 0 && froms[0] instanceof InternetAddress 
  75.242 +      && mlAddress != null)
  75.243 +    {
  75.244 +      InternetAddress from = (InternetAddress)froms[0];
  75.245 +      from.setAddress(mlAddress);
  75.246 +      msg.setFrom(from);
  75.247 +    }
  75.248 +    else
  75.249 +    {
  75.250 +      throw new MessagingException("Cannot rewrite FROM header!");
  75.251 +    }    
  75.252 +  }
  75.253 +  
  75.254 +}
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/org/sonews/mlgw/MailPoller.java	Fri Jun 26 16:48:50 2009 +0200
    76.3 @@ -0,0 +1,152 @@
    76.4 +/*
    76.5 + *   SONEWS News Server
    76.6 + *   see AUTHORS for the list of contributors
    76.7 + *
    76.8 + *   This program is free software: you can redistribute it and/or modify
    76.9 + *   it under the terms of the GNU General Public License as published by
   76.10 + *   the Free Software Foundation, either version 3 of the License, or
   76.11 + *   (at your option) any later version.
   76.12 + *
   76.13 + *   This program is distributed in the hope that it will be useful,
   76.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   76.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   76.16 + *   GNU General Public License for more details.
   76.17 + *
   76.18 + *   You should have received a copy of the GNU General Public License
   76.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   76.20 + */
   76.21 +
   76.22 +package org.sonews.mlgw;
   76.23 +
   76.24 +import java.util.Properties;
   76.25 +import javax.mail.AuthenticationFailedException;
   76.26 +import javax.mail.Authenticator;
   76.27 +import javax.mail.Flags.Flag;
   76.28 +import javax.mail.Folder;
   76.29 +import javax.mail.Message;
   76.30 +import javax.mail.MessagingException;
   76.31 +import javax.mail.NoSuchProviderException;
   76.32 +import javax.mail.PasswordAuthentication;
   76.33 +import javax.mail.Session;
   76.34 +import javax.mail.Store;
   76.35 +import org.sonews.daemon.Config;
   76.36 +import org.sonews.daemon.AbstractDaemon;
   76.37 +import org.sonews.util.Log;
   76.38 +import org.sonews.util.Stats;
   76.39 +
   76.40 +/**
   76.41 + * Daemon polling for new mails in a POP3 account to be delivered to newsgroups.
   76.42 + * @author Christian Lins
   76.43 + * @since sonews/0.5.0
   76.44 + */
   76.45 +public class MailPoller extends AbstractDaemon
   76.46 +{
   76.47 +
   76.48 +  static class PasswordAuthenticator extends Authenticator
   76.49 +  {
   76.50 +    
   76.51 +    @Override
   76.52 +    public PasswordAuthentication getPasswordAuthentication()
   76.53 +    {
   76.54 +      final String username = 
   76.55 +        Config.getInstance().get(Config.MLPOLL_USER, "user");
   76.56 +      final String password = 
   76.57 +        Config.getInstance().get(Config.MLPOLL_PASSWORD, "mysecret");
   76.58 +
   76.59 +      return new PasswordAuthentication(username, password);
   76.60 +    }
   76.61 +    
   76.62 +  }
   76.63 +  
   76.64 +  @Override
   76.65 +  public void run()
   76.66 +  {
   76.67 +    Log.msg("Starting Mailinglist Poller...", false);
   76.68 +    int errors = 0;
   76.69 +    while(isRunning() && errors < 5)
   76.70 +    {
   76.71 +      try
   76.72 +      {
   76.73 +        // Wait some time between runs. At the beginning has advantages,
   76.74 +        // because the wait is not skipped if an exception occurs.
   76.75 +        Thread.sleep(60000 * (errors + 1)); // one minute * errors
   76.76 +        
   76.77 +        final String host     = 
   76.78 +          Config.getInstance().get(Config.MLPOLL_HOST, "samplehost");
   76.79 +        final String username = 
   76.80 +          Config.getInstance().get(Config.MLPOLL_USER, "user");
   76.81 +        final String password = 
   76.82 +          Config.getInstance().get(Config.MLPOLL_PASSWORD, "mysecret");
   76.83 +        
   76.84 +        Stats.getInstance().mlgwRunStart();
   76.85 +        
   76.86 +        // Create empty properties
   76.87 +        Properties props = System.getProperties();
   76.88 +        props.put("mail.pop3.host", host);
   76.89 +
   76.90 +        // Get session
   76.91 +        Session session = Session.getInstance(props);
   76.92 +
   76.93 +        // Get the store
   76.94 +        Store store = session.getStore("pop3");
   76.95 +        store.connect(host, 110, username, password);
   76.96 +
   76.97 +        // Get folder
   76.98 +        Folder folder = store.getFolder("INBOX");
   76.99 +        folder.open(Folder.READ_WRITE);
  76.100 +
  76.101 +        // Get directory
  76.102 +        Message[] messages = folder.getMessages();
  76.103 +
  76.104 +        // Dispatch messages and delete it afterwards on the inbox
  76.105 +        for(Message message : messages)
  76.106 +        {
  76.107 +          String subject = message.getSubject();
  76.108 +          System.out.println("MLGateway: message with subject \"" + subject + "\" received.");
  76.109 +          if(Dispatcher.toGroup(message)
  76.110 +            || Config.getInstance().get(Config.MLPOLL_DELETEUNKNOWN, false))
  76.111 +          {
  76.112 +            // Delete the message
  76.113 +            message.setFlag(Flag.DELETED, true);
  76.114 +          }
  76.115 +        }
  76.116 +
  76.117 +        // Close connection 
  76.118 +        folder.close(true); // true to expunge deleted messages
  76.119 +        store.close();
  76.120 +        errors = 0;
  76.121 +        
  76.122 +        Stats.getInstance().mlgwRunEnd();
  76.123 +      }
  76.124 +      catch(NoSuchProviderException ex)
  76.125 +      {
  76.126 +        Log.msg(ex.toString(), false);
  76.127 +        shutdown();
  76.128 +      }
  76.129 +      catch(AuthenticationFailedException ex)
  76.130 +      {
  76.131 +        // AuthentificationFailedException may be thrown if credentials are
  76.132 +        // bad or if the Mailbox is in use (locked).
  76.133 +        ex.printStackTrace();
  76.134 +        errors++;
  76.135 +      }
  76.136 +      catch(InterruptedException ex)
  76.137 +      {
  76.138 +        System.out.println("sonews: " + this + " returns.");
  76.139 +        return;
  76.140 +      }
  76.141 +      catch(MessagingException ex)
  76.142 +      {
  76.143 +        ex.printStackTrace();
  76.144 +        errors++;
  76.145 +      }
  76.146 +      catch(Exception ex)
  76.147 +      {
  76.148 +        ex.printStackTrace();
  76.149 +        errors++;
  76.150 +      }
  76.151 +    }
  76.152 +    Log.msg("MailPoller exited.", false);
  76.153 +  }
  76.154 +  
  76.155 +}
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/org/sonews/mlgw/package.html	Fri Jun 26 16:48:50 2009 +0200
    77.3 @@ -0,0 +1,1 @@
    77.4 +Contains classes of the Mailinglist Gateway.
    77.5 \ No newline at end of file
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/org/sonews/util/AbstractConfig.java	Fri Jun 26 16:48:50 2009 +0200
    78.3 @@ -0,0 +1,43 @@
    78.4 +/*
    78.5 + *   SONEWS News Server
    78.6 + *   see AUTHORS for the list of contributors
    78.7 + *
    78.8 + *   This program is free software: you can redistribute it and/or modify
    78.9 + *   it under the terms of the GNU General Public License as published by
   78.10 + *   the Free Software Foundation, either version 3 of the License, or
   78.11 + *   (at your option) any later version.
   78.12 + *
   78.13 + *   This program is distributed in the hope that it will be useful,
   78.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   78.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   78.16 + *   GNU General Public License for more details.
   78.17 + *
   78.18 + *   You should have received a copy of the GNU General Public License
   78.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   78.20 + */
   78.21 +
   78.22 +package org.sonews.util;
   78.23 +
   78.24 +/**
   78.25 + * Base class for Config and BootstrapConfig.
   78.26 + * @author Christian Lins
   78.27 + * @since sonews/0.5.0
   78.28 + */
   78.29 +public abstract class AbstractConfig 
   78.30 +{
   78.31 +  
   78.32 +  public abstract String get(String key, String defVal);
   78.33 +  
   78.34 +  public int get(final String key, final int defVal)
   78.35 +  {
   78.36 +    return Integer.parseInt(
   78.37 +      get(key, Integer.toString(defVal)));
   78.38 +  }
   78.39 +  
   78.40 +  public boolean get(String key, boolean defVal)
   78.41 +  {
   78.42 +    String val = get(key, Boolean.toString(defVal));
   78.43 +    return Boolean.parseBoolean(val);
   78.44 +  }
   78.45 +  
   78.46 +}
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/org/sonews/util/DatabaseSetup.java	Fri Jun 26 16:48:50 2009 +0200
    79.3 @@ -0,0 +1,130 @@
    79.4 +/*
    79.5 + *   SONEWS News Server
    79.6 + *   see AUTHORS for the list of contributors
    79.7 + *
    79.8 + *   This program is free software: you can redistribute it and/or modify
    79.9 + *   it under the terms of the GNU General Public License as published by
   79.10 + *   the Free Software Foundation, either version 3 of the License, or
   79.11 + *   (at your option) any later version.
   79.12 + *
   79.13 + *   This program is distributed in the hope that it will be useful,
   79.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   79.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   79.16 + *   GNU General Public License for more details.
   79.17 + *
   79.18 + *   You should have received a copy of the GNU General Public License
   79.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   79.20 + */
   79.21 +
   79.22 +package org.sonews.util;
   79.23 +
   79.24 +import java.io.BufferedReader;
   79.25 +import java.io.InputStreamReader;
   79.26 +import java.sql.Connection;
   79.27 +import java.sql.DriverManager;
   79.28 +import java.sql.Statement;
   79.29 +import java.util.HashMap;
   79.30 +import java.util.Map;
   79.31 +import org.sonews.daemon.BootstrapConfig;
   79.32 +import org.sonews.util.io.Resource;
   79.33 +
   79.34 +/**
   79.35 + * Database setup utility class.
   79.36 + * @author Christian Lins
   79.37 + * @since sonews/0.5.0
   79.38 + */
   79.39 +public final class DatabaseSetup 
   79.40 +{
   79.41 +
   79.42 +  private static final Map<String, String> templateMap 
   79.43 +    = new HashMap<String, String>();
   79.44 +  private static final Map<String, StringTemplate> urlMap
   79.45 +    = new HashMap<String, StringTemplate>();
   79.46 +  private static final Map<String, String> driverMap
   79.47 +    = new HashMap<String, String>();
   79.48 +  
   79.49 +  static
   79.50 +  {
   79.51 +    templateMap.put("1", "helpers/database_mysql5_tmpl.sql");
   79.52 +    templateMap.put("2", "helpers/database_postgresql8_tmpl.sql");
   79.53 +    
   79.54 +    urlMap.put("1", new StringTemplate("jdbc:mysql://%HOSTNAME/%DB"));
   79.55 +    urlMap.put("2", new StringTemplate("jdbc:postgresql://%HOSTNAME/%DB"));
   79.56 +    
   79.57 +    driverMap.put("1", "com.mysql.jdbc.Driver");
   79.58 +    driverMap.put("2", "org.postgresql.Driver");
   79.59 +  }
   79.60 +  
   79.61 +  public static void main(String[] args)
   79.62 +    throws Exception
   79.63 +  {
   79.64 +    System.out.println("sonews Database setup helper");
   79.65 +    System.out.println("This program will create a initial database table structure");
   79.66 +    System.out.println("for the sonews Newsserver.");
   79.67 +    System.out.println("You need to create a database and a db user manually before!");
   79.68 +    
   79.69 +    System.out.println("Select DBMS type:");
   79.70 +    System.out.println("[1] MySQL 5.x or higher");
   79.71 +    System.out.println("[2] PostgreSQL 8.x or higher");
   79.72 +    System.out.print("Your choice: ");
   79.73 +    
   79.74 +    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
   79.75 +    String dbmsType = in.readLine();
   79.76 +    String tmplName = templateMap.get(dbmsType);
   79.77 +    if(tmplName == null)
   79.78 +    {
   79.79 +      System.err.println("Invalid choice. Try again you fool!");
   79.80 +      main(args);
   79.81 +      return;
   79.82 +    }
   79.83 +    
   79.84 +    // Load JDBC Driver class
   79.85 +    Class.forName(driverMap.get(dbmsType));
   79.86 +    
   79.87 +    String tmpl = Resource.getAsString(tmplName, true);
   79.88 +    
   79.89 +    System.out.print("Database server hostname (e.g. localhost): ");
   79.90 +    String dbHostname = in.readLine();
   79.91 +    
   79.92 +    System.out.print("Database name: ");
   79.93 +    String dbName = in.readLine();
   79.94 +
   79.95 +    System.out.print("Give name of DB user that can create tables: ");
   79.96 +    String dbUser = in.readLine();
   79.97 +
   79.98 +    System.out.print("Password: ");
   79.99 +    String dbPassword = in.readLine();
  79.100 +    
  79.101 +    String url = urlMap.get(dbmsType)
  79.102 +      .set("HOSTNAME", dbHostname)
  79.103 +      .set("DB", dbName).toString();
  79.104 +    
  79.105 +    Connection conn = 
  79.106 +      DriverManager.getConnection(url, dbUser, dbPassword);
  79.107 +    conn.setAutoCommit(false);
  79.108 +    
  79.109 +    String[] tmplChunks = tmpl.split(";");
  79.110 +    
  79.111 +    for(String chunk : tmplChunks)
  79.112 +    {
  79.113 +      if(chunk.trim().equals(""))
  79.114 +        continue;
  79.115 +      
  79.116 +      Statement stmt = conn.createStatement();
  79.117 +      stmt.execute(chunk);
  79.118 +    }
  79.119 +    
  79.120 +    conn.commit();
  79.121 +    conn.setAutoCommit(true);
  79.122 +    
  79.123 +    BootstrapConfig config = BootstrapConfig.getInstance();
  79.124 +    config.set(BootstrapConfig.STORAGE_DATABASE, url);
  79.125 +    config.set(BootstrapConfig.STORAGE_DBMSDRIVER, driverMap.get(dbmsType));
  79.126 +    config.set(BootstrapConfig.STORAGE_PASSWORD, dbPassword);
  79.127 +    config.set(BootstrapConfig.STORAGE_USER, dbUser);
  79.128 +    config.save();
  79.129 +    
  79.130 +    System.out.println("Ok");
  79.131 +  }
  79.132 +  
  79.133 +}
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/org/sonews/util/Log.java	Fri Jun 26 16:48:50 2009 +0200
    80.3 @@ -0,0 +1,59 @@
    80.4 +/*
    80.5 + *   SONEWS News Server
    80.6 + *   see AUTHORS for the list of contributors
    80.7 + *
    80.8 + *   This program is free software: you can redistribute it and/or modify
    80.9 + *   it under the terms of the GNU General Public License as published by
   80.10 + *   the Free Software Foundation, either version 3 of the License, or
   80.11 + *   (at your option) any later version.
   80.12 + *
   80.13 + *   This program is distributed in the hope that it will be useful,
   80.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   80.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   80.16 + *   GNU General Public License for more details.
   80.17 + *
   80.18 + *   You should have received a copy of the GNU General Public License
   80.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   80.20 + */
   80.21 +
   80.22 +package org.sonews.util;
   80.23 +
   80.24 +import org.sonews.daemon.*;
   80.25 +import java.util.Date;
   80.26 +
   80.27 +/**
   80.28 + * Provides logging and debugging methods.
   80.29 + * @author Christian Lins
   80.30 + * @since sonews/0.5.0
   80.31 + */
   80.32 +public class Log
   80.33 +{
   80.34 +  
   80.35 +  public static boolean isDebug()
   80.36 +  {
   80.37 +    // We must use BootstrapConfig here otherwise we come
   80.38 +    // into hell's kittchen when using the Logger within the
   80.39 +    // Database class.
   80.40 +    return BootstrapConfig.getInstance().get(BootstrapConfig.DEBUG, false);
   80.41 +  }
   80.42 +  
   80.43 +  /**
   80.44 +   * Writes the given message to the debug output.
   80.45 +   * @param msg A String message or an object.
   80.46 +   * @param If true this message is only shown if debug mode is enabled.
   80.47 +   */
   80.48 +  public static void msg(final Object msg, boolean debug)
   80.49 +  {
   80.50 +    if(isDebug() || !debug)
   80.51 +    {
   80.52 +      synchronized(System.out)
   80.53 +      {
   80.54 +        System.out.print(new Date().toString());
   80.55 +        System.out.print(": ");
   80.56 +        System.out.println(msg);
   80.57 +        System.out.flush();
   80.58 +      }
   80.59 +    }
   80.60 +  }
   80.61 +
   80.62 +}
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/org/sonews/util/Pair.java	Fri Jun 26 16:48:50 2009 +0200
    81.3 @@ -0,0 +1,48 @@
    81.4 +/*
    81.5 + *   SONEWS News Server
    81.6 + *   see AUTHORS for the list of contributors
    81.7 + *
    81.8 + *   This program is free software: you can redistribute it and/or modify
    81.9 + *   it under the terms of the GNU General Public License as published by
   81.10 + *   the Free Software Foundation, either version 3 of the License, or
   81.11 + *   (at your option) any later version.
   81.12 + *
   81.13 + *   This program is distributed in the hope that it will be useful,
   81.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   81.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   81.16 + *   GNU General Public License for more details.
   81.17 + *
   81.18 + *   You should have received a copy of the GNU General Public License
   81.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   81.20 + */
   81.21 +
   81.22 +package org.sonews.util;
   81.23 +
   81.24 +/**
   81.25 + * A pair of two objects.
   81.26 + * @author Christian Lins
   81.27 + * @since sonews/0.5.0
   81.28 + */
   81.29 +public class Pair<T1, T2> 
   81.30 +{
   81.31 + 
   81.32 +  private T1 a;
   81.33 +  private T2 b;
   81.34 +  
   81.35 +  public Pair(T1 a, T2 b)
   81.36 +  {
   81.37 +    this.a = a;
   81.38 +    this.b = b;
   81.39 +  }
   81.40 +
   81.41 +  public T1 getA()
   81.42 +  {
   81.43 +    return a;
   81.44 +  }
   81.45 +
   81.46 +  public T2 getB()
   81.47 +  {
   81.48 +    return b;
   81.49 +  } 
   81.50 + 
   81.51 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/org/sonews/util/Purger.java	Fri Jun 26 16:48:50 2009 +0200
    82.3 @@ -0,0 +1,88 @@
    82.4 +/*
    82.5 + *   SONEWS News Server
    82.6 + *   see AUTHORS for the list of contributors
    82.7 + *
    82.8 + *   This program is free software: you can redistribute it and/or modify
    82.9 + *   it under the terms of the GNU General Public License as published by
   82.10 + *   the Free Software Foundation, either version 3 of the License, or
   82.11 + *   (at your option) any later version.
   82.12 + *
   82.13 + *   This program is distributed in the hope that it will be useful,
   82.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   82.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   82.16 + *   GNU General Public License for more details.
   82.17 + *
   82.18 + *   You should have received a copy of the GNU General Public License
   82.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   82.20 + */
   82.21 +
   82.22 +package org.sonews.util;
   82.23 +
   82.24 +import org.sonews.daemon.Config;
   82.25 +import org.sonews.daemon.storage.Database;
   82.26 +import org.sonews.daemon.storage.Article;
   82.27 +import java.util.Date;
   82.28 +
   82.29 +/**
   82.30 + * The purger is started in configurable intervals to search
   82.31 + * for old messages that can be purged.
   82.32 + * @author Christian Lins
   82.33 + * @since sonews/0.5.0
   82.34 + */
   82.35 +public class Purger
   82.36 +{
   82.37 +
   82.38 +  private long lifetime;
   82.39 +  
   82.40 +  public Purger()
   82.41 +  {
   82.42 +    this.lifetime = Config.getInstance().get("sonews.article.lifetime", 30) 
   82.43 +      * 24L * 60L * 60L * 1000L; // in Milliseconds
   82.44 +  }
   82.45 +
   82.46 +  /**
   82.47 +   * Loops through all messages and deletes them if their time
   82.48 +   * has come.
   82.49 +   */
   82.50 +  void purge()
   82.51 +    throws Exception
   82.52 +  {
   82.53 +    System.out.println("Purging old messages...");
   82.54 +
   82.55 +    for (;;)
   82.56 +    {
   82.57 +      // TODO: Delete articles directly in database
   82.58 +      Article art = null; //Database.getInstance().getOldestArticle();
   82.59 +      if (art == null) // No articles in the database
   82.60 +      {
   82.61 +        break;
   82.62 +      }
   82.63 +
   82.64 +/*      if (art.getDate().getTime() < (new Date().getTime() + this.lifetime))
   82.65 +      {
   82.66 + //       Database.getInstance().delete(art);
   82.67 +        System.out.println("Deleted: " + art);
   82.68 +      }
   82.69 +      else
   82.70 +      {
   82.71 +        break;
   82.72 +      }*/
   82.73 +    }
   82.74 +  }
   82.75 +  
   82.76 +  public static void main(String[] args)
   82.77 +  {
   82.78 +    try
   82.79 +    {
   82.80 +      Purger purger = new Purger();
   82.81 +      purger.purge();
   82.82 +      System.exit(0);
   82.83 +    }
   82.84 +    catch(Exception ex)
   82.85 +    {
   82.86 +      ex.printStackTrace();
   82.87 +      System.exit(1);
   82.88 +    }
   82.89 +  }
   82.90 +
   82.91 +}
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/org/sonews/util/Stats.java	Fri Jun 26 16:48:50 2009 +0200
    83.3 @@ -0,0 +1,194 @@
    83.4 +/*
    83.5 + *   SONEWS News Server
    83.6 + *   see AUTHORS for the list of contributors
    83.7 + *
    83.8 + *   This program is free software: you can redistribute it and/or modify
    83.9 + *   it under the terms of the GNU General Public License as published by
   83.10 + *   the Free Software Foundation, either version 3 of the License, or
   83.11 + *   (at your option) any later version.
   83.12 + *
   83.13 + *   This program is distributed in the hope that it will be useful,
   83.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   83.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   83.16 + *   GNU General Public License for more details.
   83.17 + *
   83.18 + *   You should have received a copy of the GNU General Public License
   83.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   83.20 + */
   83.21 +
   83.22 +package org.sonews.util;
   83.23 +
   83.24 +import java.sql.SQLException;
   83.25 +import java.util.Calendar;
   83.26 +import org.sonews.daemon.storage.Database;
   83.27 +import org.sonews.daemon.storage.Group;
   83.28 +
   83.29 +/**
   83.30 + * Class that capsulates statistical data gathering.
   83.31 + * @author Christian Lins
   83.32 + * @since sonews/0.5.0
   83.33 + */
   83.34 +public final class Stats 
   83.35 +{
   83.36 +      
   83.37 +  public static final byte CONNECTIONS    = 1;
   83.38 +  public static final byte POSTED_NEWS    = 2;
   83.39 +  public static final byte GATEWAYED_NEWS = 3;
   83.40 +  public static final byte FEEDED_NEWS    = 4;
   83.41 +  public static final byte MLGW_RUNSTART  = 5;
   83.42 +  public static final byte MLGW_RUNEND    = 6;
   83.43 +
   83.44 +  private static Stats instance = new Stats();
   83.45 +  
   83.46 +  public static Stats getInstance()
   83.47 +  {
   83.48 +    return Stats.instance;
   83.49 +  }
   83.50 +  
   83.51 +  private Stats() {}
   83.52 +  
   83.53 +  private volatile int connectedClients = 0;
   83.54 +  
   83.55 +  private void addEvent(byte type, String groupname)
   83.56 +  {
   83.57 +    Group group = Group.getByName(groupname);
   83.58 +    if(group != null)
   83.59 +    {
   83.60 +      try
   83.61 +      {
   83.62 +        Database.getInstance().addEvent(
   83.63 +          System.currentTimeMillis(), type, group.getID());
   83.64 +      }
   83.65 +      catch(SQLException ex)
   83.66 +      {
   83.67 +        ex.printStackTrace();
   83.68 +      }
   83.69 +    }
   83.70 +    else
   83.71 +    {
   83.72 +      Log.msg("Group " + groupname + " does not exist.", true);
   83.73 +    }
   83.74 +  }
   83.75 +  
   83.76 +  public void clientConnect()
   83.77 +  {
   83.78 +    this.connectedClients++;
   83.79 +  }
   83.80 +  
   83.81 +  public void clientDisconnect()
   83.82 +  {
   83.83 +    this.connectedClients--;
   83.84 +  }
   83.85 +  
   83.86 +  public int connectedClients()
   83.87 +  {
   83.88 +    return this.connectedClients;
   83.89 +  }
   83.90 +  
   83.91 +  public int getNumberOfGroups()
   83.92 +  {
   83.93 +    try
   83.94 +    {
   83.95 +      return Database.getInstance().countGroups();
   83.96 +    }
   83.97 +    catch(SQLException ex)
   83.98 +    {
   83.99 +      ex.printStackTrace();
  83.100 +      return -1;
  83.101 +    }
  83.102 +  }
  83.103 +  
  83.104 +  public int getNumberOfNews()
  83.105 +  {
  83.106 +    try
  83.107 +    {
  83.108 +      return Database.getInstance().countArticles();
  83.109 +    }
  83.110 +    catch(SQLException ex)
  83.111 +    {
  83.112 +      ex.printStackTrace();
  83.113 +      return -1;
  83.114 +    }
  83.115 +  }
  83.116 +  
  83.117 +  public int getYesterdaysEvents(final byte eventType, final int hour,
  83.118 +    final Group group)
  83.119 +  {
  83.120 +    // Determine the timestamp values for yesterday and the given hour
  83.121 +    Calendar cal = Calendar.getInstance();
  83.122 +    int year  = cal.get(Calendar.YEAR);
  83.123 +    int month = cal.get(Calendar.MONTH);
  83.124 +    int dayom = cal.get(Calendar.DAY_OF_MONTH) - 1; // Yesterday
  83.125 +    
  83.126 +    cal.set(year, month, dayom, hour, 0, 0);
  83.127 +    long startTimestamp = cal.getTimeInMillis();
  83.128 +    
  83.129 +    cal.set(year, month, dayom, hour + 1, 0, 0);
  83.130 +    long endTimestamp = cal.getTimeInMillis();
  83.131 +    
  83.132 +    try
  83.133 +    {
  83.134 +      return Database.getInstance()
  83.135 +        .getEventsCount(eventType, startTimestamp, endTimestamp, group);
  83.136 +    }
  83.137 +    catch(SQLException ex)
  83.138 +    {
  83.139 +      ex.printStackTrace();
  83.140 +      return -1;
  83.141 +    }
  83.142 +  }
  83.143 +  
  83.144 +  public void mailPosted(String groupname)
  83.145 +  {
  83.146 +    addEvent(POSTED_NEWS, groupname);
  83.147 +  }
  83.148 +  
  83.149 +  public void mailGatewayed(String groupname)
  83.150 +  {
  83.151 +    addEvent(GATEWAYED_NEWS, groupname);
  83.152 +  }
  83.153 +  
  83.154 +  public void mailFeeded(String groupname)
  83.155 +  {
  83.156 +    addEvent(FEEDED_NEWS, groupname);
  83.157 +  }
  83.158 +  
  83.159 +  public void mlgwRunStart()
  83.160 +  {
  83.161 +    addEvent(MLGW_RUNSTART, "control");
  83.162 +  }
  83.163 +  
  83.164 +  public void mlgwRunEnd()
  83.165 +  {
  83.166 +    addEvent(MLGW_RUNEND, "control");
  83.167 +  }
  83.168 +  
  83.169 +  private double perHour(int key, long gid)
  83.170 +  {
  83.171 +    try
  83.172 +    {
  83.173 +      return Database.getInstance().getNumberOfEventsPerHour(key, gid);
  83.174 +    }
  83.175 +    catch(SQLException ex)
  83.176 +    {
  83.177 +      ex.printStackTrace();
  83.178 +      return -1;
  83.179 +    }
  83.180 +  }
  83.181 +  
  83.182 +  public double postedPerHour(long gid)
  83.183 +  {
  83.184 +    return perHour(POSTED_NEWS, gid);
  83.185 +  }
  83.186 +  
  83.187 +  public double gatewayedPerHour(long gid)
  83.188 +  {
  83.189 +    return perHour(GATEWAYED_NEWS, gid);
  83.190 +  }
  83.191 +  
  83.192 +  public double feededPerHour(long gid)
  83.193 +  {
  83.194 +    return perHour(FEEDED_NEWS, gid);
  83.195 +  }
  83.196 +  
  83.197 +}
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/org/sonews/util/StringTemplate.java	Fri Jun 26 16:48:50 2009 +0200
    84.3 @@ -0,0 +1,97 @@
    84.4 +/*
    84.5 + *   SONEWS News Server
    84.6 + *   see AUTHORS for the list of contributors
    84.7 + *
    84.8 + *   This program is free software: you can redistribute it and/or modify
    84.9 + *   it under the terms of the GNU General Public License as published by
   84.10 + *   the Free Software Foundation, either version 3 of the License, or
   84.11 + *   (at your option) any later version.
   84.12 + *
   84.13 + *   This program is distributed in the hope that it will be useful,
   84.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   84.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   84.16 + *   GNU General Public License for more details.
   84.17 + *
   84.18 + *   You should have received a copy of the GNU General Public License
   84.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   84.20 + */
   84.21 +
   84.22 +package org.sonews.util;
   84.23 +
   84.24 +import java.util.HashMap;
   84.25 +import java.util.Map;
   84.26 +
   84.27 +/**
   84.28 + * Class that allows simple String template handling.
   84.29 + * @author Christian Lins
   84.30 + * @since sonews/0.5.0
   84.31 + */
   84.32 +public class StringTemplate 
   84.33 +{
   84.34 +
   84.35 +  private String              str               = null;
   84.36 +  private String              templateDelimiter = "%";
   84.37 +  private Map<String, String> templateValues    = new HashMap<String, String>();
   84.38 +  
   84.39 +  public StringTemplate(String str, final String templateDelimiter)
   84.40 +  {
   84.41 +    if(str == null || templateDelimiter == null)
   84.42 +    {
   84.43 +      throw new IllegalArgumentException("null arguments not allowed");
   84.44 +    }
   84.45 +
   84.46 +    this.str               = str;
   84.47 +    this.templateDelimiter = templateDelimiter;
   84.48 +  }
   84.49 +  
   84.50 +  public StringTemplate(String str)
   84.51 +  {
   84.52 +    this(str, "%");
   84.53 +  }
   84.54 +  
   84.55 +  public StringTemplate set(String template, String value)
   84.56 +  {
   84.57 +    if(template == null || value == null)
   84.58 +    {
   84.59 +      throw new IllegalArgumentException("null arguments not allowed");
   84.60 +    }
   84.61 +    
   84.62 +    this.templateValues.put(template, value);
   84.63 +    return this;
   84.64 +  }
   84.65 +  
   84.66 +  public StringTemplate set(String template, long value)
   84.67 +  {
   84.68 +    return set(template, Long.toString(value));
   84.69 +  }
   84.70 +  
   84.71 +  public StringTemplate set(String template, double value)
   84.72 +  {
   84.73 +    return set(template, Double.toString(value));
   84.74 +  }
   84.75 +  
   84.76 +  public StringTemplate set(String template, Object obj)
   84.77 +  {
   84.78 +    if(template == null || obj == null)
   84.79 +    {
   84.80 +      throw new IllegalArgumentException("null arguments not allowed");
   84.81 +    }
   84.82 +
   84.83 +    return set(template, obj.toString());
   84.84 +  }
   84.85 +  
   84.86 +  @Override
   84.87 +  public String toString()
   84.88 +  {
   84.89 +    String ret = str;
   84.90 +
   84.91 +    for(String key : this.templateValues.keySet())
   84.92 +    {
   84.93 +      String value = this.templateValues.get(key);
   84.94 +      ret = ret.replace(templateDelimiter + key, value);
   84.95 +    }
   84.96 +    
   84.97 +    return ret;
   84.98 +  }
   84.99 +
  84.100 +}
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/org/sonews/util/TimeoutMap.java	Fri Jun 26 16:48:50 2009 +0200
    85.3 @@ -0,0 +1,145 @@
    85.4 +/*
    85.5 + *   SONEWS News Server
    85.6 + *   see AUTHORS for the list of contributors
    85.7 + *
    85.8 + *   This program is free software: you can redistribute it and/or modify
    85.9 + *   it under the terms of the GNU General Public License as published by
   85.10 + *   the Free Software Foundation, either version 3 of the License, or
   85.11 + *   (at your option) any later version.
   85.12 + *
   85.13 + *   This program is distributed in the hope that it will be useful,
   85.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   85.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   85.16 + *   GNU General Public License for more details.
   85.17 + *
   85.18 + *   You should have received a copy of the GNU General Public License
   85.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   85.20 + */
   85.21 +
   85.22 +package org.sonews.util;
   85.23 +
   85.24 +import java.util.HashMap;
   85.25 +import java.util.HashSet;
   85.26 +import java.util.Map;
   85.27 +import java.util.Set;
   85.28 +import java.util.concurrent.ConcurrentHashMap;
   85.29 +
   85.30 +/**
   85.31 + * Implementation of a Map that will loose its stored values after a 
   85.32 + * configurable amount of time.
   85.33 + * This class may be used to cache config values for example.
   85.34 + * @author Christian Lins
   85.35 + * @since sonews/0.5.0
   85.36 + */
   85.37 +public class TimeoutMap<K,V> extends ConcurrentHashMap<K, V>
   85.38 +{
   85.39 +  
   85.40 +  private static final long serialVersionUID = 453453467700345L;
   85.41 +
   85.42 +  private int                    timeout     = 60000; // 60 sec
   85.43 +  private transient Map<K, Long> timeoutMap  = new HashMap<K, Long>();
   85.44 +  
   85.45 +  /**
   85.46 +   * Constructor.
   85.47 +   * @param timeout Timeout in milliseconds
   85.48 +   */
   85.49 +  public TimeoutMap(final int timeout)
   85.50 +  {
   85.51 +    this.timeout = timeout;
   85.52 +  }
   85.53 +  
   85.54 +  /**
   85.55 +   * Uses default timeout (60 sec).
   85.56 +   */
   85.57 +  public TimeoutMap()
   85.58 +  {
   85.59 +  }
   85.60 +  
   85.61 +  /**
   85.62 +   * 
   85.63 +   * @param key
   85.64 +   * @return true if key is still valid.
   85.65 +   */
   85.66 +  protected boolean checkTimeOut(Object key)
   85.67 +  {
   85.68 +    synchronized(this.timeoutMap)
   85.69 +    {
   85.70 +      if(this.timeoutMap.containsKey(key))
   85.71 +      {
   85.72 +        long keytime = this.timeoutMap.get(key);
   85.73 +        if((System.currentTimeMillis() - keytime) < this.timeout)
   85.74 +        {
   85.75 +          return true;
   85.76 +        }
   85.77 +        else
   85.78 +        {
   85.79 +          remove(key);
   85.80 +          return false;
   85.81 +        }
   85.82 +      }
   85.83 +      else
   85.84 +      {
   85.85 +        return false;
   85.86 +      }
   85.87 +    }
   85.88 +  }
   85.89 +  
   85.90 +  @Override
   85.91 +  public boolean containsKey(Object key)
   85.92 +  {
   85.93 +    return checkTimeOut(key);
   85.94 +  }
   85.95 +
   85.96 +  @Override
   85.97 +  public synchronized V get(Object key)
   85.98 +  {
   85.99 +    if(checkTimeOut(key))
  85.100 +    {
  85.101 +      return super.get(key);
  85.102 +    }
  85.103 +    else
  85.104 +    {
  85.105 +      return null;
  85.106 +    }
  85.107 +  }
  85.108 +
  85.109 +  @Override
  85.110 +  public V put(K key, V value)
  85.111 +  {
  85.112 +    synchronized(this.timeoutMap)
  85.113 +    {
  85.114 +      removeStaleKeys();
  85.115 +      this.timeoutMap.put(key, System.currentTimeMillis());
  85.116 +      return super.put(key, value);
  85.117 +    }
  85.118 +  }
  85.119 +
  85.120 +  /**
  85.121 +   * @param arg0
  85.122 +   * @return
  85.123 +   */
  85.124 +  @Override
  85.125 +  public V remove(Object arg0)
  85.126 +  {
  85.127 +    synchronized(this.timeoutMap)
  85.128 +    {
  85.129 +      this.timeoutMap.remove(arg0);
  85.130 +      V val = super.remove(arg0);
  85.131 +      return val;
  85.132 +    }
  85.133 +  }
  85.134 +
  85.135 +  protected void removeStaleKeys()
  85.136 +  {
  85.137 +    synchronized(this.timeoutMap)
  85.138 +    {
  85.139 +      Set<Object> keySet = new HashSet<Object>(this.timeoutMap.keySet());
  85.140 +      for(Object key : keySet)
  85.141 +      {
  85.142 +        // The key/value is removed by the checkTimeOut() method if true
  85.143 +        checkTimeOut(key);
  85.144 +      }
  85.145 +    }
  85.146 +  }
  85.147 +  
  85.148 +}
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/org/sonews/util/io/ArticleInputStream.java	Fri Jun 26 16:48:50 2009 +0200
    86.3 @@ -0,0 +1,61 @@
    86.4 +/*
    86.5 + *   SONEWS News Server
    86.6 + *   see AUTHORS for the list of contributors
    86.7 + *
    86.8 + *   This program is free software: you can redistribute it and/or modify
    86.9 + *   it under the terms of the GNU General Public License as published by
   86.10 + *   the Free Software Foundation, either version 3 of the License, or
   86.11 + *   (at your option) any later version.
   86.12 + *
   86.13 + *   This program is distributed in the hope that it will be useful,
   86.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   86.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   86.16 + *   GNU General Public License for more details.
   86.17 + *
   86.18 + *   You should have received a copy of the GNU General Public License
   86.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   86.20 + */
   86.21 +
   86.22 +package org.sonews.util.io;
   86.23 +
   86.24 +import java.io.ByteArrayOutputStream;
   86.25 +import java.io.IOException;
   86.26 +import org.sonews.daemon.storage.*;
   86.27 +import java.io.InputStream;
   86.28 +import java.io.UnsupportedEncodingException;
   86.29 +
   86.30 +/**
   86.31 + * Capsulates an Article to provide a raw InputStream.
   86.32 + * @author Christian Lins
   86.33 + * @since sonews/0.5.0
   86.34 + */
   86.35 +public class ArticleInputStream extends InputStream
   86.36 +{
   86.37 +
   86.38 +  private byte[] buffer;
   86.39 +  private int    offset = 0;
   86.40 +  
   86.41 +  public ArticleInputStream(final Article art)
   86.42 +    throws IOException, UnsupportedEncodingException
   86.43 +  {
   86.44 +    final ByteArrayOutputStream out = new ByteArrayOutputStream();
   86.45 +    out.write(art.getHeaderSource().getBytes("UTF-8"));
   86.46 +    out.write("\r\n\r\n".getBytes());
   86.47 +    out.write(art.getBody().getBytes(art.getBodyCharset()));
   86.48 +    out.flush();
   86.49 +    this.buffer = out.toByteArray();
   86.50 +  }
   86.51 +  
   86.52 +  public int read()
   86.53 +  {
   86.54 +    if(offset >= buffer.length)
   86.55 +    {
   86.56 +      return -1;
   86.57 +    }
   86.58 +    else
   86.59 +    {
   86.60 +      return buffer[offset++];
   86.61 +    }
   86.62 +  }
   86.63 +  
   86.64 +}
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/org/sonews/util/io/ArticleReader.java	Fri Jun 26 16:48:50 2009 +0200
    87.3 @@ -0,0 +1,127 @@
    87.4 +/*
    87.5 + *   SONEWS News Server
    87.6 + *   see AUTHORS for the list of contributors
    87.7 + *
    87.8 + *   This program is free software: you can redistribute it and/or modify
    87.9 + *   it under the terms of the GNU General Public License as published by
   87.10 + *   the Free Software Foundation, either version 3 of the License, or
   87.11 + *   (at your option) any later version.
   87.12 + *
   87.13 + *   This program is distributed in the hope that it will be useful,
   87.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   87.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   87.16 + *   GNU General Public License for more details.
   87.17 + *
   87.18 + *   You should have received a copy of the GNU General Public License
   87.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   87.20 + */
   87.21 +
   87.22 +package org.sonews.util.io;
   87.23 +
   87.24 +import java.io.BufferedInputStream;
   87.25 +import java.io.BufferedOutputStream;
   87.26 +import java.io.ByteArrayOutputStream;
   87.27 +import java.io.IOException;
   87.28 +import java.io.InputStream;
   87.29 +import java.io.UnsupportedEncodingException;
   87.30 +import java.net.Socket;
   87.31 +import java.net.UnknownHostException;
   87.32 +import org.sonews.util.Log;
   87.33 +
   87.34 +/**
   87.35 + * Reads an news article from a NNTP server.
   87.36 + * @author Christian Lins
   87.37 + * @since sonews/0.5.0
   87.38 + */
   87.39 +public class ArticleReader 
   87.40 +{
   87.41 +
   87.42 +  private BufferedOutputStream out;
   87.43 +  private BufferedInputStream  in;
   87.44 +  private String               messageID;
   87.45 +  
   87.46 +  public ArticleReader(String host, int port, String messageID)
   87.47 +    throws IOException, UnknownHostException
   87.48 +  {
   87.49 +    this.messageID = messageID;
   87.50 +
   87.51 +    // Connect to NNTP server
   87.52 +    Socket socket = new Socket(host, port);
   87.53 +    this.out = new BufferedOutputStream(socket.getOutputStream());
   87.54 +    this.in  = new BufferedInputStream(socket.getInputStream());
   87.55 +    String line = readln(this.in);
   87.56 +    if(!line.startsWith("200 "))
   87.57 +    {
   87.58 +      throw new IOException("Invalid hello from server: " + line);
   87.59 +    }
   87.60 +  }
   87.61 +  
   87.62 +  private boolean eofArticle(byte[] buf)
   87.63 +  {
   87.64 +    if(buf.length < 4)
   87.65 +    {
   87.66 +      return false;
   87.67 +    }
   87.68 +    
   87.69 +    int l = buf.length - 1;
   87.70 +    return buf[l-3] == 10 // '*\n'
   87.71 +        && buf[l-2] == '.'                   // '.'
   87.72 +        && buf[l-1] == 13 && buf[l] == 10;  // '\r\n'
   87.73 +  }
   87.74 +  
   87.75 +  public byte[] getArticleData()
   87.76 +    throws IOException, UnsupportedEncodingException
   87.77 +  {
   87.78 +    try
   87.79 +    {
   87.80 +      this.out.write(("ARTICLE " + this.messageID + "\r\n").getBytes("UTF-8"));
   87.81 +      this.out.flush();
   87.82 +
   87.83 +      String line = readln(this.in);
   87.84 +      if(line.startsWith("220 "))
   87.85 +      {
   87.86 +        ByteArrayOutputStream buf = new ByteArrayOutputStream();
   87.87 +        
   87.88 +        while(!eofArticle(buf.toByteArray()))
   87.89 +        {
   87.90 +          for(int b = in.read(); b != 10; b = in.read())
   87.91 +          {
   87.92 +            buf.write(b);
   87.93 +          }
   87.94 +
   87.95 +          buf.write(10);
   87.96 +        }
   87.97 +        
   87.98 +        return buf.toByteArray();
   87.99 +      }
  87.100 +      else
  87.101 +      {
  87.102 +        Log.msg("ArticleReader: " + line, false);
  87.103 +        return null;
  87.104 +      }
  87.105 +    }
  87.106 +    catch(IOException ex)
  87.107 +    {
  87.108 +      throw ex;
  87.109 +    }
  87.110 +    finally
  87.111 +    {
  87.112 +      this.out.write("QUIT\r\n".getBytes("UTF-8"));
  87.113 +      this.out.flush();
  87.114 +      this.out.close();
  87.115 +    }
  87.116 +  }
  87.117 +  
  87.118 +  private String readln(InputStream in)
  87.119 +    throws IOException
  87.120 +  {
  87.121 +    ByteArrayOutputStream buf = new ByteArrayOutputStream();
  87.122 +    for(int b = in.read(); b != 10 /* \n */; b = in.read())
  87.123 +    {
  87.124 +      buf.write(b);
  87.125 +    }
  87.126 +    
  87.127 +    return new String(buf.toByteArray());
  87.128 +  }
  87.129 +
  87.130 +}
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/org/sonews/util/io/ArticleWriter.java	Fri Jun 26 16:48:50 2009 +0200
    88.3 @@ -0,0 +1,133 @@
    88.4 +/*
    88.5 + *   SONEWS News Server
    88.6 + *   see AUTHORS for the list of contributors
    88.7 + *
    88.8 + *   This program is free software: you can redistribute it and/or modify
    88.9 + *   it under the terms of the GNU General Public License as published by
   88.10 + *   the Free Software Foundation, either version 3 of the License, or
   88.11 + *   (at your option) any later version.
   88.12 + *
   88.13 + *   This program is distributed in the hope that it will be useful,
   88.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   88.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   88.16 + *   GNU General Public License for more details.
   88.17 + *
   88.18 + *   You should have received a copy of the GNU General Public License
   88.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   88.20 + */
   88.21 +
   88.22 +package org.sonews.util.io;
   88.23 +
   88.24 +import java.io.BufferedOutputStream;
   88.25 +import java.io.BufferedReader;
   88.26 +import java.io.IOException;
   88.27 +import java.io.InputStreamReader;
   88.28 +import java.io.UnsupportedEncodingException;
   88.29 +import java.net.Socket;
   88.30 +import java.net.UnknownHostException;
   88.31 +import org.sonews.daemon.storage.Article;
   88.32 +
   88.33 +/**
   88.34 + * Posts an Article to a NNTP server using the POST command.
   88.35 + * @author Christian Lins
   88.36 + * @since sonews/0.5.0
   88.37 + */
   88.38 +public class ArticleWriter 
   88.39 +{
   88.40 +  
   88.41 +  private BufferedOutputStream out;
   88.42 +  private BufferedReader       inr;
   88.43 +
   88.44 +  public ArticleWriter(String host, int port)
   88.45 +    throws IOException, UnknownHostException
   88.46 +  {
   88.47 +    // Connect to NNTP server
   88.48 +    Socket socket = new Socket(host, port);
   88.49 +    this.out = new BufferedOutputStream(socket.getOutputStream());
   88.50 +    this.inr = new BufferedReader(new InputStreamReader(socket.getInputStream()));
   88.51 +    String line = inr.readLine();
   88.52 +    if(line == null || !line.startsWith("200 "))
   88.53 +    {
   88.54 +      throw new IOException("Invalid hello from server: " + line);
   88.55 +    }
   88.56 +  }
   88.57 +  
   88.58 +  public void close()
   88.59 +    throws IOException, UnsupportedEncodingException
   88.60 +  {
   88.61 +    this.out.write("QUIT\r\n".getBytes("UTF-8"));
   88.62 +    this.out.flush();
   88.63 +  }
   88.64 +
   88.65 +  protected void finishPOST()
   88.66 +    throws IOException
   88.67 +  {
   88.68 +    this.out.write("\r\n.\r\n".getBytes());
   88.69 +    this.out.flush();
   88.70 +    String line = inr.readLine();
   88.71 +    if(line == null || !line.startsWith("240 "))
   88.72 +    {
   88.73 +      throw new IOException(line);
   88.74 +    }
   88.75 +  }
   88.76 +
   88.77 +  protected void preparePOST()
   88.78 +    throws IOException
   88.79 +  {
   88.80 +    this.out.write("POST\r\n".getBytes("UTF-8"));
   88.81 +    this.out.flush();
   88.82 +
   88.83 +    String line = this.inr.readLine();
   88.84 +    if(line == null || !line.startsWith("340 "))
   88.85 +    {
   88.86 +      throw new IOException(line);
   88.87 +    }
   88.88 +  }
   88.89 +
   88.90 +  public void writeArticle(Article article)
   88.91 +    throws IOException, UnsupportedEncodingException
   88.92 +  {
   88.93 +    byte[] buf = new byte[512];
   88.94 +    ArticleInputStream in = new ArticleInputStream(article);
   88.95 +
   88.96 +    preparePOST();
   88.97 +    
   88.98 +    int len = in.read(buf);
   88.99 +    while(len != -1)
  88.100 +    {
  88.101 +      writeLine(buf, len);
  88.102 +      len = in.read(buf);
  88.103 +    }
  88.104 +
  88.105 +    finishPOST();
  88.106 +  }
  88.107 +
  88.108 +  /**
  88.109 +   * Writes the raw content of an article to the remote server. This method
  88.110 +   * does no charset conversion/handling of any kind so its the preferred
  88.111 +   * method for sending an article to remote peers.
  88.112 +   * @param rawArticle
  88.113 +   * @throws IOException
  88.114 +   */
  88.115 +  public void writeArticle(byte[] rawArticle)
  88.116 +    throws IOException
  88.117 +  {
  88.118 +    preparePOST();
  88.119 +    writeLine(rawArticle, rawArticle.length);
  88.120 +    finishPOST();
  88.121 +  }
  88.122 +
  88.123 +  /**
  88.124 +   * Writes the given buffer to the connect remote server.
  88.125 +   * @param buffer
  88.126 +   * @param len
  88.127 +   * @throws IOException
  88.128 +   */
  88.129 +  protected void writeLine(byte[] buffer, int len)
  88.130 +    throws IOException
  88.131 +  {
  88.132 +    this.out.write(buffer, 0, len);
  88.133 +    this.out.flush();
  88.134 +  }
  88.135 +
  88.136 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/org/sonews/util/io/Resource.java	Fri Jun 26 16:48:50 2009 +0200
    89.3 @@ -0,0 +1,132 @@
    89.4 +/*
    89.5 + *   SONEWS News Server
    89.6 + *   see AUTHORS for the list of contributors
    89.7 + *
    89.8 + *   This program is free software: you can redistribute it and/or modify
    89.9 + *   it under the terms of the GNU General Public License as published by
   89.10 + *   the Free Software Foundation, either version 3 of the License, or
   89.11 + *   (at your option) any later version.
   89.12 + *
   89.13 + *   This program is distributed in the hope that it will be useful,
   89.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   89.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   89.16 + *   GNU General Public License for more details.
   89.17 + *
   89.18 + *   You should have received a copy of the GNU General Public License
   89.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   89.20 + */
   89.21 +
   89.22 +package org.sonews.util.io;
   89.23 +
   89.24 +import java.io.BufferedReader;
   89.25 +import java.io.IOException;
   89.26 +import java.io.InputStream;
   89.27 +import java.io.InputStreamReader;
   89.28 +import java.net.URL;
   89.29 +import java.nio.charset.Charset;
   89.30 +
   89.31 +/**
   89.32 + * Provides method for loading of resources.
   89.33 + * @author Christian Lins
   89.34 + * @since sonews/0.5.0
   89.35 + */
   89.36 +public final class Resource
   89.37 +{
   89.38 +  
   89.39 +  /**
   89.40 +   * Loads a resource and returns it as URL reference.
   89.41 +   * The Resource's classloader is used to load the resource, not
   89.42 +   * the System's ClassLoader so it may be safe to use this method
   89.43 +   * in a sandboxed environment.
   89.44 +   * @return
   89.45 +   */
   89.46 +  public static URL getAsURL(final String name)
   89.47 +  {
   89.48 +    if(name == null)
   89.49 +    {
   89.50 +      return null;
   89.51 +    }
   89.52 +
   89.53 +    return Resource.class.getClassLoader().getResource(name);
   89.54 +  }
   89.55 +  
   89.56 +  /**
   89.57 +   * Loads a resource and returns an InputStream to it.
   89.58 +   * @param name
   89.59 +   * @return
   89.60 +   */
   89.61 +  public static InputStream getAsStream(String name)
   89.62 +  {
   89.63 +    try
   89.64 +    {
   89.65 +      URL url = getAsURL(name);
   89.66 +      if(url == null)
   89.67 +      {
   89.68 +        return null;
   89.69 +      }
   89.70 +      else
   89.71 +      {
   89.72 +        return url.openStream();
   89.73 +      }
   89.74 +    }
   89.75 +    catch(IOException e)
   89.76 +    {
   89.77 +      e.printStackTrace();
   89.78 +      return null;
   89.79 +    }
   89.80 +  }
   89.81 +
   89.82 +  /**
   89.83 +   * Loads a plain text resource.
   89.84 +   * @param withNewline If false all newlines are removed from the 
   89.85 +   * return String
   89.86 +   */
   89.87 +  public static String getAsString(String name, boolean withNewline)
   89.88 +  {
   89.89 +    if(name == null)
   89.90 +      return null;
   89.91 +
   89.92 +    BufferedReader in = null;
   89.93 +    try
   89.94 +    {
   89.95 +      InputStream ins = getAsStream(name);
   89.96 +      if(ins == null)
   89.97 +        return null;
   89.98 +
   89.99 +      in = new BufferedReader(
  89.100 +        new InputStreamReader(ins, Charset.forName("UTF-8")));
  89.101 +      StringBuffer buf = new StringBuffer();
  89.102 +
  89.103 +      for(;;)
  89.104 +      {
  89.105 +        String line = in.readLine();
  89.106 +        if(line == null)
  89.107 +          break;
  89.108 +
  89.109 +        buf.append(line);
  89.110 +        if(withNewline)
  89.111 +          buf.append('\n');
  89.112 +      }
  89.113 +
  89.114 +      return buf.toString();
  89.115 +    }
  89.116 +    catch(Exception e)
  89.117 +    {
  89.118 +      e.printStackTrace();
  89.119 +      return null;
  89.120 +    }
  89.121 +    finally
  89.122 +    {
  89.123 +      try
  89.124 +      {
  89.125 +        if(in != null)
  89.126 +          in.close();
  89.127 +      }
  89.128 +      catch(IOException ex)
  89.129 +      {
  89.130 +        ex.printStackTrace();
  89.131 +      }
  89.132 +    }
  89.133 +  }
  89.134 +
  89.135 +}
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/org/sonews/util/io/VarCharsetReader.java	Fri Jun 26 16:48:50 2009 +0200
    90.3 @@ -0,0 +1,90 @@
    90.4 +/*
    90.5 + *   SONEWS News Server
    90.6 + *   see AUTHORS for the list of contributors
    90.7 + *
    90.8 + *   This program is free software: you can redistribute it and/or modify
    90.9 + *   it under the terms of the GNU General Public License as published by
   90.10 + *   the Free Software Foundation, either version 3 of the License, or
   90.11 + *   (at your option) any later version.
   90.12 + *
   90.13 + *   This program is distributed in the hope that it will be useful,
   90.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   90.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   90.16 + *   GNU General Public License for more details.
   90.17 + *
   90.18 + *   You should have received a copy of the GNU General Public License
   90.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   90.20 + */
   90.21 +
   90.22 +package org.sonews.util.io;
   90.23 +
   90.24 +import java.io.IOException;
   90.25 +import java.io.InputStream;
   90.26 +import java.nio.ByteBuffer;
   90.27 +import java.nio.charset.Charset;
   90.28 +
   90.29 +/**
   90.30 + * InputStream that can change its decoding charset while reading from the
   90.31 + * underlying byte based stream.
   90.32 + * @author Christian Lins
   90.33 + * @since sonews/0.5.0
   90.34 + */
   90.35 +public class VarCharsetReader
   90.36 +{
   90.37 +
   90.38 +  private final ByteBuffer buf = ByteBuffer.allocate(4096);
   90.39 +  private InputStream in;
   90.40 +  
   90.41 +  public VarCharsetReader(final InputStream in)
   90.42 +  {
   90.43 +    if(in == null)
   90.44 +    {
   90.45 +      throw new IllegalArgumentException("null InputStream");
   90.46 +    }
   90.47 +    this.in = in;
   90.48 +  }
   90.49 +  
   90.50 +  /**
   90.51 +   * Reads up to the next newline character and returns the line as String.
   90.52 +   * The String is decoded using the given charset.
   90.53 +   */
   90.54 +  public String readLine(Charset charset)
   90.55 +    throws IOException
   90.56 +  {    
   90.57 +    byte[] byteBuf = new byte[1];
   90.58 +    String bufStr;
   90.59 +    
   90.60 +    for(;;)
   90.61 +    {
   90.62 +      int read = this.in.read(byteBuf);
   90.63 +      if(read == 0)
   90.64 +      {
   90.65 +        continue;
   90.66 +      }
   90.67 +      else if(read == -1)
   90.68 +      {
   90.69 +        this.in = null;
   90.70 +        bufStr  = new String(this.buf.array(), 0, this.buf.position(), charset);
   90.71 +        break;
   90.72 +      }
   90.73 +      else if(byteBuf[0] == 10) // Is this safe? \n
   90.74 +      {
   90.75 +        bufStr  = new String(this.buf.array(), 0, this.buf.position(), charset);
   90.76 +        break;
   90.77 +      }
   90.78 +      else if(byteBuf[0] == 13) // \r
   90.79 +      { // Skip
   90.80 +        continue;
   90.81 +      }
   90.82 +      else
   90.83 +      {
   90.84 +        this.buf.put(byteBuf[0]);
   90.85 +      }
   90.86 +    }
   90.87 +    
   90.88 +    this.buf.clear();
   90.89 +    
   90.90 +    return bufStr;
   90.91 +  }
   90.92 +  
   90.93 +}
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/org/sonews/util/io/package.html	Fri Jun 26 16:48:50 2009 +0200
    91.3 @@ -0,0 +1,1 @@
    91.4 +Contains I/O utilitiy classes.
    91.5 \ No newline at end of file
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/org/sonews/util/package.html	Fri Jun 26 16:48:50 2009 +0200
    92.3 @@ -0,0 +1,1 @@
    92.4 +Contains various utility classes.
    92.5 \ No newline at end of file
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/org/sonews/web/AbstractSonewsServlet.java	Fri Jun 26 16:48:50 2009 +0200
    93.3 @@ -0,0 +1,113 @@
    93.4 +/*
    93.5 + *   SONEWS News Server
    93.6 + *   see AUTHORS for the list of contributors
    93.7 + *
    93.8 + *   This program is free software: you can redistribute it and/or modify
    93.9 + *   it under the terms of the GNU General Public License as published by
   93.10 + *   the Free Software Foundation, either version 3 of the License, or
   93.11 + *   (at your option) any later version.
   93.12 + *
   93.13 + *   This program is distributed in the hope that it will be useful,
   93.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   93.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   93.16 + *   GNU General Public License for more details.
   93.17 + *
   93.18 + *   You should have received a copy of the GNU General Public License
   93.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   93.20 + */
   93.21 +
   93.22 +package org.sonews.web;
   93.23 +
   93.24 +import java.io.BufferedReader;
   93.25 +import java.io.IOException;
   93.26 +import java.io.InputStreamReader;
   93.27 +import java.io.PrintWriter;
   93.28 +import java.net.Socket;
   93.29 +import javax.servlet.http.HttpServlet;
   93.30 +import org.sonews.util.StringTemplate;
   93.31 +import org.sonews.util.io.Resource;
   93.32 +
   93.33 +/**
   93.34 + * Base class for all sonews servlets.
   93.35 + * @author Christian Lins
   93.36 + * @since sonews/0.5.0
   93.37 + */
   93.38 +public class AbstractSonewsServlet extends HttpServlet
   93.39 +{
   93.40 +
   93.41 +  public static final String TemplateRoot = "org/sonews/web/tmpl/";
   93.42 +  
   93.43 +  protected String        hello = null;
   93.44 +  
   93.45 +  private BufferedReader  in     = null;
   93.46 +  private PrintWriter     out    = null;
   93.47 +  private Socket          socket = null;
   93.48 +  
   93.49 +  protected void connectToNewsserver()
   93.50 +    throws IOException
   93.51 +  {
   93.52 +    // Get sonews port from properties
   93.53 +    String port = System.getProperty("sonews.port", "9119");
   93.54 +    String host = System.getProperty("sonews.host", "localhost");
   93.55 +    
   93.56 +    try
   93.57 +    {
   93.58 +      this.socket = new Socket(host, Integer.parseInt(port));
   93.59 +
   93.60 +      this.in     = new BufferedReader(
   93.61 +        new InputStreamReader(socket.getInputStream()));
   93.62 +      this.out = new PrintWriter(socket.getOutputStream());
   93.63 +
   93.64 +      hello = in.readLine(); // Read hello message
   93.65 +    }
   93.66 +    catch(IOException ex)
   93.67 +    {
   93.68 +      System.out.println("sonews.host=" + host);
   93.69 +      System.out.println("sonews.port=" + port);
   93.70 +      System.out.flush();
   93.71 +      throw ex;
   93.72 +    }
   93.73 +  }
   93.74 +  
   93.75 +  protected void disconnectFromNewsserver()
   93.76 +  {
   93.77 +    try
   93.78 +    {
   93.79 +      printlnToNewsserver("QUIT");
   93.80 +      out.close();
   93.81 +      readlnFromNewsserver(); // Wait for bye message
   93.82 +      in.close();
   93.83 +      socket.close();
   93.84 +    }
   93.85 +    catch(IOException ex)
   93.86 +    {
   93.87 +      ex.printStackTrace();
   93.88 +    }
   93.89 +  }
   93.90 +  
   93.91 +  protected StringTemplate getTemplate(String res)
   93.92 +  {
   93.93 +    StringTemplate tmpl = new StringTemplate(
   93.94 +      Resource.getAsString(TemplateRoot + "AbstractSonewsServlet.tmpl", true));
   93.95 +    String content    = Resource.getAsString(TemplateRoot + res, true);
   93.96 +    String stylesheet = System.getProperty("sonews.web.stylesheet", "style.css");
   93.97 +    
   93.98 +    tmpl.set("CONTENT", content);
   93.99 +    tmpl.set("STYLESHEET", stylesheet);
  93.100 +    
  93.101 +    return new StringTemplate(tmpl.toString());
  93.102 +  }
  93.103 +  
  93.104 +  protected void printlnToNewsserver(final String line)
  93.105 +  {
  93.106 +    this.out.println(line);
  93.107 +    this.out.flush();
  93.108 +  }
  93.109 +  
  93.110 +  protected String readlnFromNewsserver()
  93.111 +    throws IOException
  93.112 +  {
  93.113 +    return this.in.readLine();
  93.114 +  }
  93.115 +  
  93.116 +}
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/org/sonews/web/MemoryBitmapChart.java	Fri Jun 26 16:48:50 2009 +0200
    94.3 @@ -0,0 +1,61 @@
    94.4 +/*
    94.5 + *   SONEWS News Server
    94.6 + *   see AUTHORS for the list of contributors
    94.7 + *
    94.8 + *   This program is free software: you can redistribute it and/or modify
    94.9 + *   it under the terms of the GNU General Public License as published by
   94.10 + *   the Free Software Foundation, either version 3 of the License, or
   94.11 + *   (at your option) any later version.
   94.12 + *
   94.13 + *   This program is distributed in the hope that it will be useful,
   94.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   94.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   94.16 + *   GNU General Public License for more details.
   94.17 + *
   94.18 + *   You should have received a copy of the GNU General Public License
   94.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   94.20 + */
   94.21 +
   94.22 +package org.sonews.web;
   94.23 +
   94.24 +import info.monitorenter.gui.chart.Chart2D;
   94.25 +import info.monitorenter.gui.chart.IAxis.AxisTitle;
   94.26 +import java.awt.Color;
   94.27 +import java.awt.image.BufferedImage;
   94.28 +import java.io.ByteArrayOutputStream;
   94.29 +import java.io.IOException;
   94.30 +import javax.imageio.ImageIO;
   94.31 +
   94.32 +/**
   94.33 + * A chart rendered to a memory bitmap.
   94.34 + * @author Christian Lins
   94.35 + * @since sonews/0.5.0
   94.36 + */
   94.37 +class MemoryBitmapChart extends Chart2D
   94.38 +{
   94.39 +
   94.40 +  public MemoryBitmapChart()
   94.41 +  {
   94.42 +    setGridColor(Color.LIGHT_GRAY);
   94.43 +    getAxisX().setPaintGrid(true);
   94.44 +    getAxisY().setPaintGrid(true);
   94.45 +    getAxisX().setAxisTitle(new AxisTitle("time of day"));
   94.46 +    getAxisY().setAxisTitle(new AxisTitle("processed news"));
   94.47 +  }
   94.48 +  
   94.49 +  public String getContentType()
   94.50 +  {
   94.51 +    return "image/png";
   94.52 +  }
   94.53 +  
   94.54 +  public byte[] getRawData(final int width, final int height)
   94.55 +    throws IOException
   94.56 +  {
   94.57 +    setSize(width, height);
   94.58 +    BufferedImage img = snapShot(width, height);
   94.59 +    ByteArrayOutputStream out = new ByteArrayOutputStream();
   94.60 +    ImageIO.write(img, "png", out);
   94.61 +    return out.toByteArray();
   94.62 +  }
   94.63 +  
   94.64 +}
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/org/sonews/web/SonewsChartServlet.java	Fri Jun 26 16:48:50 2009 +0200
    95.3 @@ -0,0 +1,114 @@
    95.4 +/*
    95.5 + *   SONEWS News Server
    95.6 + *   see AUTHORS for the list of contributors
    95.7 + *
    95.8 + *   This program is free software: you can redistribute it and/or modify
    95.9 + *   it under the terms of the GNU General Public License as published by
   95.10 + *   the Free Software Foundation, either version 3 of the License, or
   95.11 + *   (at your option) any later version.
   95.12 + *
   95.13 + *   This program is distributed in the hope that it will be useful,
   95.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   95.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   95.16 + *   GNU General Public License for more details.
   95.17 + *
   95.18 + *   You should have received a copy of the GNU General Public License
   95.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   95.20 + */
   95.21 +
   95.22 +package org.sonews.web;
   95.23 +
   95.24 +import info.monitorenter.gui.chart.ITrace2D;
   95.25 +import info.monitorenter.gui.chart.traces.Trace2DSimple;
   95.26 +import java.io.IOException;
   95.27 +import javax.servlet.http.HttpServletRequest;
   95.28 +import javax.servlet.http.HttpServletResponse;
   95.29 +
   95.30 +/**
   95.31 + * Servlet that creates chart images and returns them as raw PNG images.
   95.32 + * @author Christian Lins
   95.33 + * @since sonews/0.5.0
   95.34 + */
   95.35 +public class SonewsChartServlet extends AbstractSonewsServlet
   95.36 +{
   95.37 +  
   95.38 +  private ITrace2D createProcessMails24(String title, String cmd)
   95.39 +    throws IOException
   95.40 +  {
   95.41 +    int[] data = read24Values(cmd);
   95.42 +    ITrace2D trace = new Trace2DSimple(title);
   95.43 +    trace.addPoint(0.0, 0.0); // Start
   95.44 +    
   95.45 +    for(int n = 0; n < 24; n++)
   95.46 +    {
   95.47 +      trace.addPoint(n, data[n]);
   95.48 +    }
   95.49 +
   95.50 +    return trace;
   95.51 +  }
   95.52 +  
   95.53 +  @Override
   95.54 +  public void doGet(HttpServletRequest req, HttpServletResponse resp)
   95.55 +    throws IOException
   95.56 +  {
   95.57 +    synchronized(this)
   95.58 +    {
   95.59 +      MemoryBitmapChart chart = new MemoryBitmapChart();
   95.60 +
   95.61 +      String name  = req.getParameter("name");
   95.62 +      String group = req.getParameter("group");
   95.63 +      ITrace2D trace;
   95.64 +      String   cmd = "XDAEMON LOG";
   95.65 +
   95.66 +      if(name.equals("feedednewsyesterday"))
   95.67 +      {
   95.68 +        cmd = cmd + " TRANSMITTED_NEWS";
   95.69 +        cmd = group != null ? cmd + " " + group : cmd;
   95.70 +        trace = createProcessMails24(
   95.71 +          "To peers transmitted mails yesterday", cmd);
   95.72 +      }
   95.73 +      else if(name.equals("gatewayednewsyesterday"))
   95.74 +      {
   95.75 +        cmd = cmd + " GATEWAYED_NEWS";
   95.76 +        cmd = group != null ? cmd + " " + group : cmd;
   95.77 +        trace = createProcessMails24(
   95.78 +          "Gatewayed mails yesterday", cmd);
   95.79 +      }
   95.80 +      else
   95.81 +      {
   95.82 +        cmd = cmd + " POSTED_NEWS";
   95.83 +        cmd = group != null ? cmd + " " + group : cmd;
   95.84 +        trace = createProcessMails24(
   95.85 +          "Posted mails yesterday", cmd);
   95.86 +      }
   95.87 +      chart.addTrace(trace);
   95.88 +
   95.89 +      resp.getOutputStream().write(chart.getRawData(500, 400));
   95.90 +      resp.setContentType(chart.getContentType());
   95.91 +      resp.setStatus(HttpServletResponse.SC_OK);
   95.92 +    }
   95.93 +  }
   95.94 +  
   95.95 +  private int[] read24Values(String command)
   95.96 +    throws IOException
   95.97 +  {
   95.98 +    int[] values = new int[24];
   95.99 +    connectToNewsserver();
  95.100 +    printlnToNewsserver(command);
  95.101 +    String line = readlnFromNewsserver();
  95.102 +    if(!line.startsWith("200 "))
  95.103 +      throw new IOException(command + " not supported!");
  95.104 +    
  95.105 +    for(int n = 0; n < 24; n++)
  95.106 +    {
  95.107 +      line = readlnFromNewsserver();
  95.108 +      values[n] = Integer.parseInt(line.split(" ")[1]);
  95.109 +    }
  95.110 +    
  95.111 +    line = readlnFromNewsserver(); // "."
  95.112 +    
  95.113 +    disconnectFromNewsserver();
  95.114 +    return values;
  95.115 +  }
  95.116 +  
  95.117 +}
    96.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    96.2 +++ b/org/sonews/web/SonewsConfigServlet.java	Fri Jun 26 16:48:50 2009 +0200
    96.3 @@ -0,0 +1,239 @@
    96.4 +/*
    96.5 + *   SONEWS News Server
    96.6 + *   see AUTHORS for the list of contributors
    96.7 + *
    96.8 + *   This program is free software: you can redistribute it and/or modify
    96.9 + *   it under the terms of the GNU General Public License as published by
   96.10 + *   the Free Software Foundation, either version 3 of the License, or
   96.11 + *   (at your option) any later version.
   96.12 + *
   96.13 + *   This program is distributed in the hope that it will be useful,
   96.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   96.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   96.16 + *   GNU General Public License for more details.
   96.17 + *
   96.18 + *   You should have received a copy of the GNU General Public License
   96.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   96.20 + */
   96.21 +
   96.22 +package org.sonews.web;
   96.23 +
   96.24 +import java.io.IOException;
   96.25 +import java.util.ArrayList;
   96.26 +import java.util.List;
   96.27 +import java.util.Set;
   96.28 +import javax.servlet.http.HttpServletRequest;
   96.29 +import javax.servlet.http.HttpServletResponse;
   96.30 +import org.sonews.util.StringTemplate;
   96.31 +import org.sonews.util.io.Resource;
   96.32 +
   96.33 +/**
   96.34 + * Servlet providing a configuration web interface.
   96.35 + * @author Christian Lins
   96.36 + * @since sonews/0.5.0
   96.37 + */
   96.38 +public class SonewsConfigServlet extends AbstractSonewsServlet
   96.39 +{
   96.40 +  
   96.41 +  private static final long serialVersionUID = 2432543253L;
   96.42 +  
   96.43 +  @Override
   96.44 +  public void doGet(HttpServletRequest req, HttpServletResponse resp)
   96.45 +    throws IOException
   96.46 +  {
   96.47 +    synchronized(this)
   96.48 +    {
   96.49 +      connectToNewsserver();
   96.50 +      String which = req.getParameter("which");
   96.51 +
   96.52 +      if(which != null && which.equals("config"))
   96.53 +      {
   96.54 +        whichConfig(req, resp);
   96.55 +      }
   96.56 +      else if(which != null && which.equals("groupadd"))
   96.57 +      {
   96.58 +        whichGroupAdd(req, resp);
   96.59 +      }
   96.60 +      else if(which != null && which.equals("groupdelete"))
   96.61 +      {
   96.62 +        whichGroupDelete(req, resp);
   96.63 +      }
   96.64 +      else
   96.65 +      {
   96.66 +        whichNone(req, resp);
   96.67 +      }
   96.68 +
   96.69 +      disconnectFromNewsserver();
   96.70 +    }
   96.71 +  }
   96.72 +  
   96.73 +  private void whichConfig(HttpServletRequest req, HttpServletResponse resp)
   96.74 +    throws IOException
   96.75 +  {
   96.76 +    StringBuilder keys = new StringBuilder();
   96.77 +
   96.78 +    Set pnames = req.getParameterMap().keySet();
   96.79 +    for(Object obj : pnames)
   96.80 +    {
   96.81 +      String pname = (String)obj;
   96.82 +      if(pname.startsWith("configkey:"))
   96.83 +      {
   96.84 +        String value = req.getParameter(pname);
   96.85 +        String key   = pname.split(":")[1];
   96.86 +        if(!value.equals("<not set>"))
   96.87 +        {
   96.88 +          printlnToNewsserver("XDAEMON SET " + key + " " + value);
   96.89 +          readlnFromNewsserver();
   96.90 +          
   96.91 +          keys.append(key); 
   96.92 +          keys.append("<br/>");
   96.93 +        }
   96.94 +      }
   96.95 +    }
   96.96 +    
   96.97 +    StringTemplate tmpl = getTemplate("ConfigUpdated.tmpl");
   96.98 +    
   96.99 +    tmpl.set("UPDATED_KEYS", keys.toString());
  96.100 +    
  96.101 +    resp.setStatus(HttpServletResponse.SC_OK);
  96.102 +    resp.getWriter().println(tmpl.toString());
  96.103 +    resp.getWriter().flush();
  96.104 +  }
  96.105 +  
  96.106 +  private void whichGroupAdd(HttpServletRequest req, HttpServletResponse resp)
  96.107 +    throws IOException
  96.108 +  {
  96.109 +    String[] groupnames = req.getParameter("groups").split("\n");
  96.110 +    
  96.111 +    for(String groupname : groupnames)
  96.112 +    {
  96.113 +      groupname = groupname.trim();
  96.114 +      if(groupname.equals(""))
  96.115 +      {
  96.116 +        continue;
  96.117 +      }
  96.118 +
  96.119 +      printlnToNewsserver("XDAEMON GROUPADD " + groupname + " 0");
  96.120 +      String line = readlnFromNewsserver();
  96.121 +      if(!line.startsWith("200 "))
  96.122 +      {
  96.123 +        System.out.println("Warning " + groupname + " probably not created!");
  96.124 +      }
  96.125 +    }
  96.126 +    
  96.127 +    StringTemplate tmpl = getTemplate("GroupAdded.tmpl");
  96.128 +    
  96.129 +    tmpl.set("GROUP", req.getParameter("groups"));
  96.130 +    
  96.131 +    resp.setStatus(HttpServletResponse.SC_OK);
  96.132 +    resp.getWriter().println(tmpl.toString());
  96.133 +    resp.getWriter().flush();
  96.134 +  }
  96.135 +  
  96.136 +  private void whichGroupDelete(HttpServletRequest req, HttpServletResponse resp)
  96.137 +    throws IOException
  96.138 +  {
  96.139 +    String groupname = req.getParameter("group");
  96.140 +    printlnToNewsserver("XDAEMON GROUPDEL " + groupname);
  96.141 +    String line = readlnFromNewsserver();
  96.142 +    if(!line.startsWith("200 "))
  96.143 +      throw new IOException(line);
  96.144 +    
  96.145 +    StringTemplate tmpl = getTemplate("GroupDeleted.tmpl");
  96.146 +    
  96.147 +    tmpl.set("GROUP", groupname);
  96.148 +    
  96.149 +    resp.setStatus(HttpServletResponse.SC_OK);
  96.150 +    resp.getWriter().println(tmpl.toString());
  96.151 +    resp.getWriter().flush();
  96.152 +  }
  96.153 +  
  96.154 +  private void whichNone(HttpServletRequest req, HttpServletResponse resp)
  96.155 +    throws IOException
  96.156 +  {
  96.157 +    StringTemplate tmpl = getTemplate("SonewsConfigServlet.tmpl");
  96.158 +    
  96.159 +    // Retrieve config keys from server
  96.160 +    List<String> configKeys = new ArrayList<String>();
  96.161 +    printlnToNewsserver("XDAEMON LIST CONFIGKEYS");
  96.162 +    String line = readlnFromNewsserver();
  96.163 +    if(!line.startsWith("200 "))
  96.164 +      throw new IOException("XDAEMON command not supported!");
  96.165 +    for(;;)
  96.166 +    {
  96.167 +      line = readlnFromNewsserver();
  96.168 +      if(line.equals("."))
  96.169 +        break;
  96.170 +      else
  96.171 +        configKeys.add(line);
  96.172 +    }
  96.173 +    
  96.174 +    // Construct config table
  96.175 +    StringBuilder strb = new StringBuilder();
  96.176 +    for(String key : configKeys)
  96.177 +    {
  96.178 +      strb.append("<tr><td><code>");
  96.179 +      strb.append(key);
  96.180 +      strb.append("</code></td><td>");
  96.181 +      
  96.182 +      // Retrieve config value from server
  96.183 +      String value = "<not set>";
  96.184 +      printlnToNewsserver("XDAEMON GET " + key);
  96.185 +      line = readlnFromNewsserver();
  96.186 +      if(line.startsWith("200 "))
  96.187 +      {
  96.188 +        value = readlnFromNewsserver();
  96.189 +        readlnFromNewsserver(); // Read the "."
  96.190 +      }
  96.191 +      
  96.192 +      strb.append("<input type=text name=\"configkey:");
  96.193 +      strb.append(key);
  96.194 +      strb.append("\" value=\"");
  96.195 +      strb.append(value);
  96.196 +      strb.append("\"/></td></tr>");
  96.197 +    }
  96.198 +    tmpl.set("CONFIG", strb.toString());
  96.199 +    
  96.200 +    // Retrieve served newsgroup names from server
  96.201 +    List<String> groups = new ArrayList<String>();
  96.202 +    printlnToNewsserver("LIST");
  96.203 +    line = readlnFromNewsserver();
  96.204 +    if(line.startsWith("215 "))
  96.205 +    {
  96.206 +      for(;;)
  96.207 +      {
  96.208 +        line = readlnFromNewsserver();
  96.209 +        if(line.equals("."))
  96.210 +        {
  96.211 +          break;
  96.212 +        }
  96.213 +        else
  96.214 +        {
  96.215 +          groups.add(line.split(" ")[0]);
  96.216 +        }
  96.217 +      }
  96.218 +    }
  96.219 +    else
  96.220 +      throw new IOException("Error issuing LIST command!");
  96.221 +    
  96.222 +    // Construct groups list
  96.223 +    StringTemplate tmplGroupList = new StringTemplate(
  96.224 +      Resource.getAsString("org/sonews/web/tmpl/GroupList.tmpl", true));
  96.225 +    strb = new StringBuilder();
  96.226 +    for(String group : groups)
  96.227 +    {
  96.228 +      tmplGroupList.set("GROUPNAME", group);
  96.229 +      strb.append(tmplGroupList.toString());
  96.230 +    }
  96.231 +    tmpl.set("GROUP", strb.toString());
  96.232 +    
  96.233 +    // Set server name
  96.234 +    tmpl.set("SERVERNAME", hello.split(" ")[2]);
  96.235 +    tmpl.set("TITLE", "Configuration");
  96.236 +    
  96.237 +    resp.getWriter().println(tmpl.toString());
  96.238 +    resp.getWriter().flush();
  96.239 +    resp.setStatus(HttpServletResponse.SC_OK);
  96.240 +  }
  96.241 +
  96.242 +}
    97.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    97.2 +++ b/org/sonews/web/SonewsGroupServlet.java	Fri Jun 26 16:48:50 2009 +0200
    97.3 @@ -0,0 +1,66 @@
    97.4 +/*
    97.5 + *   SONEWS News Server
    97.6 + *   see AUTHORS for the list of contributors
    97.7 + *
    97.8 + *   This program is free software: you can redistribute it and/or modify
    97.9 + *   it under the terms of the GNU General Public License as published by
   97.10 + *   the Free Software Foundation, either version 3 of the License, or
   97.11 + *   (at your option) any later version.
   97.12 + *
   97.13 + *   This program is distributed in the hope that it will be useful,
   97.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   97.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   97.16 + *   GNU General Public License for more details.
   97.17 + *
   97.18 + *   You should have received a copy of the GNU General Public License
   97.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   97.20 + */
   97.21 +
   97.22 +package org.sonews.web;
   97.23 +
   97.24 +import java.io.IOException;
   97.25 +import javax.servlet.http.HttpServletRequest;
   97.26 +import javax.servlet.http.HttpServletResponse;
   97.27 +import org.sonews.util.StringTemplate;
   97.28 +
   97.29 +/**
   97.30 + * Views the group settings and allows editing.
   97.31 + * @author Christian Lins
   97.32 + * @since sonews/0.5.0
   97.33 + */
   97.34 +public class SonewsGroupServlet extends AbstractSonewsServlet
   97.35 +{
   97.36 +
   97.37 +  @Override
   97.38 +  public void doGet(HttpServletRequest req, HttpServletResponse resp)
   97.39 +    throws IOException
   97.40 +  {
   97.41 +    synchronized(this)
   97.42 +    {
   97.43 +      connectToNewsserver();
   97.44 +      String name   = req.getParameter("name");
   97.45 +      String action = req.getParameter("action");
   97.46 +
   97.47 +      if("set_flags".equals(action))
   97.48 +      {
   97.49 +
   97.50 +      }
   97.51 +      else if("set_mladdress".equals(action))
   97.52 +      {
   97.53 +        
   97.54 +      }
   97.55 +
   97.56 +      StringTemplate tmpl = getTemplate("SonewsGroupServlet.tmpl");
   97.57 +      tmpl.set("SERVERNAME", hello.split(" ")[2]);
   97.58 +      tmpl.set("TITLE", "Group " + name);
   97.59 +      tmpl.set("GROUPNAME", name);
   97.60 +
   97.61 +      resp.getWriter().println(tmpl.toString());
   97.62 +      resp.getWriter().flush();
   97.63 +      resp.setStatus(HttpServletResponse.SC_OK);
   97.64 +
   97.65 +      disconnectFromNewsserver();
   97.66 +    }
   97.67 +  }
   97.68 +  
   97.69 +}
    98.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.2 +++ b/org/sonews/web/SonewsPeerServlet.java	Fri Jun 26 16:48:50 2009 +0200
    98.3 @@ -0,0 +1,95 @@
    98.4 +/*
    98.5 + *   SONEWS News Server
    98.6 + *   see AUTHORS for the list of contributors
    98.7 + *
    98.8 + *   This program is free software: you can redistribute it and/or modify
    98.9 + *   it under the terms of the GNU General Public License as published by
   98.10 + *   the Free Software Foundation, either version 3 of the License, or
   98.11 + *   (at your option) any later version.
   98.12 + *
   98.13 + *   This program is distributed in the hope that it will be useful,
   98.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   98.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   98.16 + *   GNU General Public License for more details.
   98.17 + *
   98.18 + *   You should have received a copy of the GNU General Public License
   98.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   98.20 + */
   98.21 +
   98.22 +package org.sonews.web;
   98.23 +
   98.24 +import java.io.IOException;
   98.25 +import java.util.HashSet;
   98.26 +import javax.servlet.http.HttpServletRequest;
   98.27 +import javax.servlet.http.HttpServletResponse;
   98.28 +import org.sonews.util.StringTemplate;
   98.29 +
   98.30 +/**
   98.31 + * Servlet that shows the Peers and the Peering Rules.
   98.32 + * @author Christian Lins
   98.33 + * @since sonews/0.5.0
   98.34 + */
   98.35 +public class SonewsPeerServlet extends AbstractSonewsServlet
   98.36 +{
   98.37 +
   98.38 +  private static final long serialVersionUID = 245345346356L;
   98.39 +  
   98.40 +  @Override
   98.41 +  public void doGet(HttpServletRequest req, HttpServletResponse resp)
   98.42 +    throws IOException
   98.43 +  {
   98.44 +    synchronized(this)
   98.45 +    {
   98.46 +      connectToNewsserver();
   98.47 +      StringTemplate tmpl = getTemplate("SonewsPeerServlet.tmpl");
   98.48 +
   98.49 +      // Read peering rules from newsserver
   98.50 +      printlnToNewsserver("XDAEMON LIST PEERINGRULES");
   98.51 +      String line = readlnFromNewsserver();
   98.52 +      if(!line.startsWith("200 "))
   98.53 +      {
   98.54 +        throw new IOException("Unexpected reply: " + line);
   98.55 +      }
   98.56 +
   98.57 +      // Create FEED_RULES String
   98.58 +      HashSet<String> peers        = new HashSet<String>();
   98.59 +      StringBuilder   feedRulesStr = new StringBuilder();
   98.60 +      for(;;)
   98.61 +      {
   98.62 +        line = readlnFromNewsserver();
   98.63 +        if(line.equals("."))
   98.64 +        {
   98.65 +          break;
   98.66 +        }
   98.67 +        else
   98.68 +        {
   98.69 +          feedRulesStr.append(line);
   98.70 +          feedRulesStr.append("<br/>");
   98.71 +
   98.72 +          String[] lineChunks = line.split(" ");
   98.73 +          peers.add(lineChunks[1]);
   98.74 +        }
   98.75 +      }
   98.76 +
   98.77 +      // Create PEERS string
   98.78 +      StringBuilder peersStr = new StringBuilder();
   98.79 +      for(String peer : peers)
   98.80 +      {
   98.81 +        peersStr.append(peer);
   98.82 +        peersStr.append("<br/>");
   98.83 +      }
   98.84 +
   98.85 +      // Set server name
   98.86 +      tmpl.set("PEERS", peersStr.toString());
   98.87 +      tmpl.set("PEERING_RULES", feedRulesStr.toString());
   98.88 +      tmpl.set("SERVERNAME", hello.split(" ")[2]);
   98.89 +      tmpl.set("TITLE", "Peers");
   98.90 +
   98.91 +      resp.getWriter().println(tmpl.toString());
   98.92 +      resp.getWriter().flush();
   98.93 +      resp.setStatus(HttpServletResponse.SC_OK);
   98.94 +      disconnectFromNewsserver();
   98.95 +    }
   98.96 +  }
   98.97 +  
   98.98 +}
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/org/sonews/web/SonewsServlet.java	Fri Jun 26 16:48:50 2009 +0200
    99.3 @@ -0,0 +1,127 @@
    99.4 +/*
    99.5 + *   SONEWS News Server
    99.6 + *   see AUTHORS for the list of contributors
    99.7 + *
    99.8 + *   This program is free software: you can redistribute it and/or modify
    99.9 + *   it under the terms of the GNU General Public License as published by
   99.10 + *   the Free Software Foundation, either version 3 of the License, or
   99.11 + *   (at your option) any later version.
   99.12 + *
   99.13 + *   This program is distributed in the hope that it will be useful,
   99.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   99.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   99.16 + *   GNU General Public License for more details.
   99.17 + *
   99.18 + *   You should have received a copy of the GNU General Public License
   99.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   99.20 + */
   99.21 +
   99.22 +package org.sonews.web;
   99.23 +
   99.24 +import java.io.IOException;
   99.25 +import javax.servlet.http.HttpServletRequest;
   99.26 +import javax.servlet.http.HttpServletResponse;
   99.27 +import org.sonews.daemon.Main;
   99.28 +import org.sonews.util.StringTemplate;
   99.29 +
   99.30 +/**
   99.31 + * Main sonews webpage servlet.
   99.32 + * @author Christian Lins
   99.33 + * @since sonews/0.5.0
   99.34 + */
   99.35 +public class SonewsServlet extends AbstractSonewsServlet
   99.36 +{
   99.37 +
   99.38 +  private static final long serialVersionUID = 2392837459834L;
   99.39 +
   99.40 +  @Override
   99.41 +  public void doGet(HttpServletRequest res, HttpServletResponse resp)
   99.42 +    throws IOException
   99.43 +  {
   99.44 +    synchronized(this)
   99.45 +    {
   99.46 +      connectToNewsserver();
   99.47 +
   99.48 +      String line;
   99.49 +      int    connectedClients = 0;
   99.50 +      int    hostedGroups     = 0;
   99.51 +      int    hostedNews       = 0;
   99.52 +
   99.53 +      printlnToNewsserver("XDAEMON LOG CONNECTED_CLIENTS");
   99.54 +
   99.55 +      line = readlnFromNewsserver();
   99.56 +      if(!line.startsWith("200 "))
   99.57 +      {
   99.58 +        throw new IOException("XDAEMON command not allowed by server");
   99.59 +      }
   99.60 +      line = readlnFromNewsserver();
   99.61 +      connectedClients = Integer.parseInt(line);
   99.62 +      line = readlnFromNewsserver(); // Read the "."
   99.63 +
   99.64 +      printlnToNewsserver("XDAEMON LOG HOSTED_NEWS");
   99.65 +      line = readlnFromNewsserver();
   99.66 +      if(!line.startsWith("200 "))
   99.67 +      {
   99.68 +        throw new IOException("XDAEMON command not allowed by server");
   99.69 +      }
   99.70 +      line = readlnFromNewsserver();
   99.71 +      hostedNews = Integer.parseInt(line);
   99.72 +      line = readlnFromNewsserver(); // read the "."
   99.73 +
   99.74 +      printlnToNewsserver("XDAEMON LOG HOSTED_GROUPS");
   99.75 +      line = readlnFromNewsserver();
   99.76 +      if(!line.startsWith("200 "))
   99.77 +      {
   99.78 +        throw new IOException("XDAEMON command not allowed by server");
   99.79 +      }
   99.80 +      line = readlnFromNewsserver();
   99.81 +      hostedGroups = Integer.parseInt(line);
   99.82 +      line = readlnFromNewsserver(); // read the "."
   99.83 +
   99.84 +      printlnToNewsserver("XDAEMON LOG POSTED_NEWS_PER_HOUR");
   99.85 +      line = readlnFromNewsserver();
   99.86 +      if(!line.startsWith("200 "))
   99.87 +      {
   99.88 +        throw new IOException("XDAEMON command not allowed by server");
   99.89 +      }
   99.90 +      String postedNewsPerHour = readlnFromNewsserver();
   99.91 +      readlnFromNewsserver();
   99.92 +
   99.93 +      printlnToNewsserver("XDAEMON LOG GATEWAYED_NEWS_PER_HOUR");
   99.94 +      line = readlnFromNewsserver();
   99.95 +      if(!line.startsWith("200 "))
   99.96 +      {
   99.97 +        throw new IOException("XDAEMON command not allowed by server");
   99.98 +      }
   99.99 +      String gatewayedNewsPerHour = readlnFromNewsserver();
  99.100 +      line = readlnFromNewsserver();
  99.101 +
  99.102 +      printlnToNewsserver("XDAEMON LOG FEEDED_NEWS_PER_HOUR");
  99.103 +      line = readlnFromNewsserver();
  99.104 +      if(!line.startsWith("200 "))
  99.105 +      {
  99.106 +        throw new IOException("XDAEMON command not allowed by server");
  99.107 +      }
  99.108 +      String feededNewsPerHour = readlnFromNewsserver();
  99.109 +      line = readlnFromNewsserver();
  99.110 +
  99.111 +      StringTemplate tmpl = getTemplate("SonewsServlet.tmpl");
  99.112 +      tmpl.set("SERVERNAME", hello.split(" ")[2]);
  99.113 +      tmpl.set("STARTDATE", Main.STARTDATE);
  99.114 +      tmpl.set("ACTIVE_CONNECTIONS", connectedClients);
  99.115 +      tmpl.set("STORED_NEWS", hostedNews);
  99.116 +      tmpl.set("SERVED_NEWSGROUPS", hostedGroups);
  99.117 +      tmpl.set("POSTED_NEWS", postedNewsPerHour);
  99.118 +      tmpl.set("GATEWAYED_NEWS", gatewayedNewsPerHour);
  99.119 +      tmpl.set("FEEDED_NEWS", feededNewsPerHour);
  99.120 +      tmpl.set("TITLE", "Overview");
  99.121 +
  99.122 +      resp.getWriter().println(tmpl.toString());
  99.123 +      resp.getWriter().flush();
  99.124 +      resp.setStatus(HttpServletResponse.SC_OK);
  99.125 +
  99.126 +      disconnectFromNewsserver();
  99.127 +    }
  99.128 +  }
  99.129 +  
  99.130 +}
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/org/sonews/web/package.html	Fri Jun 26 16:48:50 2009 +0200
   100.3 @@ -0,0 +1,3 @@
   100.4 +Contains classes of the sonews web interface. These classes are not needed by
   100.5 +the running sonews daemon but by the Servlet container 
   100.6 +<a href="http://kitten.sonews.org/">Kitten</a>.
   100.7 \ No newline at end of file
   101.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   101.2 +++ b/org/sonews/web/tmpl/AbstractSonewsServlet.tmpl	Fri Jun 26 16:48:50 2009 +0200
   101.3 @@ -0,0 +1,14 @@
   101.4 +<html>
   101.5 +<head>
   101.6 +  <title>%SERVERNAME - %TITLE</title>
   101.7 +  <link rel="stylesheet" type="text/css" href="%STYLESHEET" />
   101.8 +</head>
   101.9 +
  101.10 +<body>
  101.11 +<div class="pagetitle">sonews - %TITLE</div>
  101.12 +
  101.13 +<div class="content">
  101.14 +%CONTENT
  101.15 +</div>
  101.16 +</body>
  101.17 +</html>
  101.18 \ No newline at end of file
   102.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   102.2 +++ b/org/sonews/web/tmpl/ConfigUpdated.tmpl	Fri Jun 26 16:48:50 2009 +0200
   102.3 @@ -0,0 +1,7 @@
   102.4 +  <p>
   102.5 +    The following config keys were updated: <br/>
   102.6 +    %UPDATED_KEYS
   102.7 +  </p>
   102.8 +  <p>
   102.9 +    <a href="/sonews/config">Back to Config</a>
  102.10 +  </p>
  102.11 \ No newline at end of file
   103.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.2 +++ b/org/sonews/web/tmpl/GroupAdded.tmpl	Fri Jun 26 16:48:50 2009 +0200
   103.3 @@ -0,0 +1,6 @@
   103.4 +  <p>
   103.5 +    The Newsgroup %GROUP has been created!
   103.6 +  </p>
   103.7 +  <p>
   103.8 +    <a href="/sonews/config">Back to Config</a>
   103.9 +  </p>
  103.10 \ No newline at end of file
   104.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.2 +++ b/org/sonews/web/tmpl/GroupDeleted.tmpl	Fri Jun 26 16:48:50 2009 +0200
   104.3 @@ -0,0 +1,6 @@
   104.4 +  <p>
   104.5 +    The Newsgroup %GROUP and all associated articles have been deleted!
   104.6 +  </p>
   104.7 +  <p>
   104.8 +    <a href="/sonews/config">Back to Config</a>
   104.9 +  </p>
  104.10 \ No newline at end of file
   105.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   105.2 +++ b/org/sonews/web/tmpl/GroupList.tmpl	Fri Jun 26 16:48:50 2009 +0200
   105.3 @@ -0,0 +1,8 @@
   105.4 +<tr>
   105.5 +  <td>
   105.6 +    <a href="/sonews/group?name=%GROUPNAME">%GROUPNAME</a>
   105.7 +  </td>
   105.8 +  <td>
   105.9 +    <a href="?which=groupdelete&group=%GROUPNAME">delete</a>
  105.10 +  </td>
  105.11 +</tr>
  105.12 \ No newline at end of file
   106.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.2 +++ b/org/sonews/web/tmpl/SonewsConfigServlet.tmpl	Fri Jun 26 16:48:50 2009 +0200
   106.3 @@ -0,0 +1,30 @@
   106.4 +<p>
   106.5 +<a href="/sonews">Back to Main Page</a>
   106.6 +</p>
   106.7 +
   106.8 +<h2>Configuration values</h2>
   106.9 +<form action="/sonews/config" method="GET">
  106.10 +<input type="hidden" name="which" value="config"/>
  106.11 +<table>
  106.12 +%CONFIG
  106.13 +</table>
  106.14 +<input type="submit" value="Apply changes"/>
  106.15 +</form>
  106.16 +
  106.17 +<h2>Groups served by this sonews instance</h2>
  106.18 +<table>
  106.19 +%GROUP
  106.20 +</table>
  106.21 +
  106.22 +<p>
  106.23 +<h2>Add new group to be served</h2>
  106.24 +<form action="/sonews/config" method="GET">
  106.25 +  <input type="hidden" name="which" value="groupadd"/>
  106.26 +<table>
  106.27 +  <tr><td>Names (separated by newlines):</td>
  106.28 +      <td><textarea cols="50" rows="15" name="groups"></textarea></td></tr>
  106.29 +  </tr>
  106.30 +</table>
  106.31 +<input type="submit" value="Add groups"/>
  106.32 +</form>
  106.33 +</p>
  106.34 \ No newline at end of file
   107.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.2 +++ b/org/sonews/web/tmpl/SonewsGroupServlet.tmpl	Fri Jun 26 16:48:50 2009 +0200
   107.3 @@ -0,0 +1,36 @@
   107.4 +<p>
   107.5 +<a href="/sonews">Back to Main Page</a>
   107.6 +</p>
   107.7 +
   107.8 +<h1>Group %GROUPNAME</h1>
   107.9 +
  107.10 +<h2>Configuration</h2>
  107.11 +<h3>General</h3>
  107.12 +<form action="" method="GET">
  107.13 +  <input type="hidden" name="name" value="%GROUPNAME" />
  107.14 +  <input type="hidden" name="action" value="set_flags"/>
  107.15 +  Is mirrored Mailinglist?:
  107.16 +  <input type="checkbox" name="flag0" value="true" />
  107.17 +  <br/>
  107.18 +  <input type="submit" value="Update" />
  107.19 +</form>
  107.20 +
  107.21 +<h3>Mailinglist</h3>
  107.22 +<form action="" method="GET">
  107.23 +  <input type="hidden" name="name" value="%GROUPNAME" />
  107.24 +  <input type="hidden" name="action" value="set_mladdress"/>
  107.25 +  Mailinglist address:
  107.26 +  <input type="text" name="mladdress" />
  107.27 +  <br/>
  107.28 +  <input type="submit" value="Update" />
  107.29 +</form>
  107.30 +
  107.31 +<h2>Statistics</h2>
  107.32 +<h3>Posted mails yesterday</h3>
  107.33 +<img src="/sonews/chart?name=postednewsyesterday&group=%GROUPNAME" />
  107.34 +
  107.35 +<h3>Gatewayed mails yesterday</h3>
  107.36 +<img src="/sonews/chart?name=gatewayednewsyesterday&group=%GROUPNAME" />
  107.37 +
  107.38 +<h3>Feeded news</h3>
  107.39 +<img src="/sonews/chart?name=feedednewsyesterday&group=%GROUPNAME" />
  107.40 \ No newline at end of file
   108.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   108.2 +++ b/org/sonews/web/tmpl/SonewsPeerServlet.tmpl	Fri Jun 26 16:48:50 2009 +0200
   108.3 @@ -0,0 +1,52 @@
   108.4 +<p>
   108.5 +<a href="/sonews">Back to Main Page</a>
   108.6 +</p>
   108.7 +
   108.8 +On this page you can configure to which peer hosts new messages are 
   108.9 +posted or from which peer hosts we should receive messages.
  108.10 +
  108.11 +<h2>Peers</h2>
  108.12 +%PEERS
  108.13 +
  108.14 +<h3>Add new peer</h3>
  108.15 +<form action="" method="GET">
  108.16 +<table style="border: 0px">
  108.17 +  <tr>
  108.18 +    <td>Hostname:</td>
  108.19 +    <td><input type="text" name="host" value="news.someremotehost.org" /></td>
  108.20 +  </tr>
  108.21 +  <tr>
  108.22 +    <td>Port:</td>
  108.23 +    <td><input type="text" name="port" value="119" /></td>
  108.24 +  </tr>
  108.25 +</table>
  108.26 +<input type="submit" value="Add peer" />
  108.27 +</form>
  108.28 +
  108.29 +<h2>Rules</h2>
  108.30 +<h3>Current</h3>
  108.31 +%PEERING_RULES
  108.32 +
  108.33 +<h3>Add peering rule</h3>
  108.34 +<form action="" method="GET">
  108.35 +<table style="border: 0px">
  108.36 +  <tr>
  108.37 +    <td>Peer:</td>
  108.38 +    <td>%OPTION_PEERS</td>
  108.39 +  </tr>
  108.40 +  <tr>
  108.41 +    <td>Group:</td>
  108.42 +    <td>%OPTION_GROUP</td>
  108.43 +  </tr>
  108.44 +  <tr>
  108.45 +    <td>Peering type:</td>
  108.46 +    <td>
  108.47 +      <select name="peertype">
  108.48 +        <option value="0">Pull peering</option>
  108.49 +        <option value="1">Push peering</option>
  108.50 +      </select>
  108.51 +    </td>
  108.52 +  </tr>
  108.53 +</table>
  108.54 +<input type="submit" value="Add peering rule" />
  108.55 +</form>
  108.56 \ No newline at end of file
   109.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   109.2 +++ b/org/sonews/web/tmpl/SonewsServlet.tmpl	Fri Jun 26 16:48:50 2009 +0200
   109.3 @@ -0,0 +1,54 @@
   109.4 +This server is running since %STARTDATE.
   109.5 +
   109.6 +<h2>Configuration</h2>
   109.7 +Here you can edit most of the configuration values for %SERVERNAME.
   109.8 +Please note that some of these values require a server restart, 
   109.9 +some do not and are valid immediately.
  109.10 +<ul>
  109.11 +  <li><a href="/sonews/config">View/Edit configuration values</a></li>
  109.12 +  <li><a href="/sonews/peer">View/Edit peer settings</a></li>
  109.13 +</ul>
  109.14 +
  109.15 +<h2>Statistics & Logs</h2>
  109.16 +Here is a short overview of useful statistics of %SERVERNAME. Click on a
  109.17 +stat key to get more details.
  109.18 +<table style="border: 1px dotted black">
  109.19 +  <tr>
  109.20 +    <td><i>Stat key</i></td>
  109.21 +    <td><i>Value</i></td>
  109.22 +  </tr>
  109.23 +
  109.24 +  <tr>
  109.25 +    <td>Active connections:</td>
  109.26 +    <td>%ACTIVE_CONNECTIONS</td>
  109.27 +  </tr>
  109.28 +
  109.29 +  <tr>
  109.30 +    <td>Served newsgroups:</td>
  109.31 +    <td>%SERVED_NEWSGROUPS</td>
  109.32 +  </tr>
  109.33 +
  109.34 +  <tr>
  109.35 +    <td>Stored news messages:</td>
  109.36 +    <td>%STORED_NEWS</td>
  109.37 +  </tr>
  109.38 +
  109.39 +  <tr>
  109.40 +    <td><a href="/sonews/chart?name=postednewsyesterday">Posted news</a>:</td>
  109.41 +    <td>%POSTED_NEWS per hour</td>
  109.42 +  </tr>
  109.43 +
  109.44 +  <tr>
  109.45 +    <td><a href="/sonews/chart?name=gatewayednewsyesterday">Gatewayed news</a>:</td>
  109.46 +    <td>%GATEWAYED_NEWS per hour</td>
  109.47 +  </tr>
  109.48 +
  109.49 +  <tr>
  109.50 +    <td><a href="/sonews/chart?name=feedednewsyesterday">Feeded news</a>:</td>
  109.51 +    <td>%FEEDED_NEWS per hour</td>
  109.52 +  </tr>
  109.53 +</table>
  109.54 +
  109.55 +<h2>Documentation</h2>
  109.56 +You'll find the most recent 
  109.57 +<a href="http://www.sonews.org/">documentation of %SERVERNAME here</a>.
  109.58 \ No newline at end of file
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/test/AbstractTest.java	Fri Jun 26 16:48:50 2009 +0200
   110.3 @@ -0,0 +1,93 @@
   110.4 +/*
   110.5 + *   StarOffice News Server
   110.6 + *   see AUTHORS for the list of contributors
   110.7 + *
   110.8 + *   This program is free software: you can redistribute it and/or modify
   110.9 + *   it under the terms of the GNU General Public License as published by
  110.10 + *   the Free Software Foundation, either version 3 of the License, or
  110.11 + *   (at your option) any later version.
  110.12 + *
  110.13 + *   This program is distributed in the hope that it will be useful,
  110.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  110.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  110.16 + *   GNU General Public License for more details.
  110.17 + *
  110.18 + *   You should have received a copy of the GNU General Public License
  110.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  110.20 + */
  110.21 +
  110.22 +package test;
  110.23 +
  110.24 +import java.io.BufferedReader;
  110.25 +import java.io.File;
  110.26 +import java.io.IOException;
  110.27 +import java.io.InputStreamReader;
  110.28 +import java.io.PrintWriter;
  110.29 +import java.net.Socket;
  110.30 +import java.net.UnknownHostException;
  110.31 +
  110.32 +/**
  110.33 + * Base class for every test performed by the TestBench. 
  110.34 + * Connects to a NNTP Server and provides basic methods for sending and
  110.35 + * receiving data.
  110.36 + * @author Christian Lins
  110.37 + * @since sonews/0.5.0
  110.38 + */
  110.39 +public abstract class AbstractTest
  110.40 +{
  110.41 +
  110.42 +  protected static PrintWriter log;
  110.43 +  
  110.44 +  static
  110.45 +  {
  110.46 +    try
  110.47 +    {
  110.48 +      log = new PrintWriter(new File("test.log"));
  110.49 +    }
  110.50 +    catch(Exception ex)
  110.51 +    {
  110.52 +      ex.printStackTrace();
  110.53 +    }
  110.54 +  }
  110.55 +  
  110.56 +  protected BufferedReader  in;
  110.57 +  protected PrintWriter     out;
  110.58 +  protected Socket          socket;
  110.59 +  
  110.60 +  /**
  110.61 +   * Connects to NNTP Server using for
  110.62 +   * @param host
  110.63 +   * @param port
  110.64 +   * @throws java.io.IOException
  110.65 +   * @throws java.net.UnknownHostException
  110.66 +   */
  110.67 +  public void connect(String host, int port)
  110.68 +    throws IOException, UnknownHostException
  110.69 +  {
  110.70 +    socket = new Socket(host, port);
  110.71 +    socket.setSoTimeout(10000);
  110.72 +    this.in  = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  110.73 +    this.out = new PrintWriter(socket.getOutputStream());
  110.74 +  }
  110.75 +  
  110.76 +  protected void println(String line)
  110.77 +  {
  110.78 +    this.out.println(line);
  110.79 +    this.out.flush();
  110.80 +    
  110.81 +    log.println(">> " + line);
  110.82 +    log.flush();
  110.83 +  }
  110.84 +  
  110.85 +  protected String readln()
  110.86 +    throws IOException
  110.87 +  {
  110.88 +    String line = this.in.readLine();
  110.89 +    log.println("<< " + line);
  110.90 +    log.flush();
  110.91 +    return line;
  110.92 +  }
  110.93 +  
  110.94 +  public abstract int runTest() throws Exception;
  110.95 +  
  110.96 +}
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/test/CollectionsSpeedTest.java	Fri Jun 26 16:48:50 2009 +0200
   111.3 @@ -0,0 +1,72 @@
   111.4 +/*
   111.5 + *   StarOffice News Server
   111.6 + *   see AUTHORS for the list of contributors
   111.7 + *
   111.8 + *   This program is free software: you can redistribute it and/or modify
   111.9 + *   it under the terms of the GNU General Public License as published by
  111.10 + *   the Free Software Foundation, either version 3 of the License, or
  111.11 + *   (at your option) any later version.
  111.12 + *
  111.13 + *   This program is distributed in the hope that it will be useful,
  111.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  111.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  111.16 + *   GNU General Public License for more details.
  111.17 + *
  111.18 + *   You should have received a copy of the GNU General Public License
  111.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  111.20 + */
  111.21 +
  111.22 +package test;
  111.23 +
  111.24 +import java.util.ArrayList;
  111.25 +import java.util.LinkedList;
  111.26 +import java.util.List;
  111.27 +import java.util.ListIterator;
  111.28 +
  111.29 +/**
  111.30 + * Tests the speed of LinkedList and ArrayList.
  111.31 + * @author Christian Lins
  111.32 + * @since sonews/0.5.0
  111.33 + */
  111.34 +public class CollectionsSpeedTest 
  111.35 +{
  111.36 +
  111.37 +  public static void main(String[] args)
  111.38 +  {
  111.39 +    List arrayList  = new ArrayList();
  111.40 +    List linkedList = new LinkedList();
  111.41 +    
  111.42 +    int numElements = 100000;
  111.43 +    
  111.44 +    System.out.println("ArrayList.add(): " + add(arrayList, numElements) + "ms");
  111.45 +    System.out.println("LinkenList.add(): " + add(linkedList, numElements) + "ms");
  111.46 +    System.out.println("ArrayList.iterate: " + iterate(arrayList) + "ms");
  111.47 +    System.out.println("LinkedList.iterate: " + iterate(linkedList) + "ms");
  111.48 +  }
  111.49 +  
  111.50 +  private static long add(List list, int numElements)
  111.51 +  {
  111.52 +    long start = System.currentTimeMillis();
  111.53 +    
  111.54 +    for(int n = 0; n < numElements; n++)
  111.55 +    {
  111.56 +      list.add(new Object());
  111.57 +    }
  111.58 +    
  111.59 +    return System.currentTimeMillis() - start;
  111.60 +  }
  111.61 +  
  111.62 +  private static long iterate(List list)
  111.63 +  {
  111.64 +    long start = System.currentTimeMillis();
  111.65 +    
  111.66 +    ListIterator iter = list.listIterator();
  111.67 +    while(iter.hasNext())
  111.68 +    {
  111.69 +      iter.next();
  111.70 +    }
  111.71 +    
  111.72 +    return System.currentTimeMillis() - start;
  111.73 +  }
  111.74 +  
  111.75 +}
   112.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   112.2 +++ b/test/PerfTest.java	Fri Jun 26 16:48:50 2009 +0200
   112.3 @@ -0,0 +1,44 @@
   112.4 +/*
   112.5 + *   StarOffice News Server
   112.6 + *   see AUTHORS for the list of contributors
   112.7 + *
   112.8 + *   This program is free software: you can redistribute it and/or modify
   112.9 + *   it under the terms of the GNU General Public License as published by
  112.10 + *   the Free Software Foundation, either version 3 of the License, or
  112.11 + *   (at your option) any later version.
  112.12 + *
  112.13 + *   This program is distributed in the hope that it will be useful,
  112.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  112.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  112.16 + *   GNU General Public License for more details.
  112.17 + *
  112.18 + *   You should have received a copy of the GNU General Public License
  112.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  112.20 + */
  112.21 +
  112.22 +package test;
  112.23 +
  112.24 +/**
  112.25 + * Opens a connection, waits for Hello and exits while leaving the connection
  112.26 + * open until SoTimeout.
  112.27 + * @author Christian Lins
  112.28 + * @since sonews/0.5.0
  112.29 + */
  112.30 +public class PerfTest extends AbstractTest
  112.31 +{
  112.32 +
  112.33 +  @Override
  112.34 +  public int runTest() throws Exception
  112.35 +  {
  112.36 +    String line = readln();
  112.37 +    if(!line.startsWith("200 "))
  112.38 +    {
  112.39 +      return 1;
  112.40 +    }
  112.41 +    
  112.42 +    socket.setSoTimeout(0);
  112.43 +    
  112.44 +    return 0;
  112.45 +  }
  112.46 +
  112.47 +}
   113.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   113.2 +++ b/test/PerfTestBench.java	Fri Jun 26 16:48:50 2009 +0200
   113.3 @@ -0,0 +1,63 @@
   113.4 +/*
   113.5 + *   StarOffice News Server
   113.6 + *   see AUTHORS for the list of contributors
   113.7 + *
   113.8 + *   This program is free software: you can redistribute it and/or modify
   113.9 + *   it under the terms of the GNU General Public License as published by
  113.10 + *   the Free Software Foundation, either version 3 of the License, or
  113.11 + *   (at your option) any later version.
  113.12 + *
  113.13 + *   This program is distributed in the hope that it will be useful,
  113.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  113.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  113.16 + *   GNU General Public License for more details.
  113.17 + *
  113.18 + *   You should have received a copy of the GNU General Public License
  113.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  113.20 + */
  113.21 +
  113.22 +package test;
  113.23 +
  113.24 +/**
  113.25 + * TestBench that performs a - yes - performance test. The test runs until
  113.26 + * the opened sockets reach the systems maximum. The test has now valid end
  113.27 + * as it will throw IOErrors at the end.
  113.28 + * @author Christian Lins
  113.29 + * @since sonews/0.5.0
  113.30 + */
  113.31 +public class PerfTestBench 
  113.32 +{
  113.33 +
  113.34 +  public static void main(String[] args)
  113.35 +    throws Exception
  113.36 +  {
  113.37 +    System.out.println("Performance TestBench for NNTP (RFC3799) based servers ");
  113.38 +    if(args.length < 1)
  113.39 +    {
  113.40 +      System.out.println("Usage: TestBench <host>[:port]");
  113.41 +      return;
  113.42 +    }
  113.43 +    
  113.44 +    String[] hostport = args[0].split(":");
  113.45 +    String host = hostport[0];
  113.46 +    int    port = 119;
  113.47 +    if(hostport.length == 2)
  113.48 +    {
  113.49 +      port = Integer.parseInt(hostport[1]);
  113.50 +    }
  113.51 +    
  113.52 +    for(int n = 0; true; n++)
  113.53 +    {
  113.54 +      PerfTest pf = new PerfTest();
  113.55 +      pf.connect(host, port);
  113.56 +      pf.runTest();
  113.57 +      
  113.58 +      if(n % 100 == 0)
  113.59 +      {
  113.60 +        System.out.println("Test #" + n);
  113.61 +        System.out.flush();
  113.62 +      }
  113.63 +    }
  113.64 +  }
  113.65 +  
  113.66 +}
   114.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   114.2 +++ b/test/StringTemplateTest.java	Fri Jun 26 16:48:50 2009 +0200
   114.3 @@ -0,0 +1,43 @@
   114.4 +/*
   114.5 + *   StarOffice News Server
   114.6 + *   see AUTHORS for the list of contributors
   114.7 + *
   114.8 + *   This program is free software: you can redistribute it and/or modify
   114.9 + *   it under the terms of the GNU General Public License as published by
  114.10 + *   the Free Software Foundation, either version 3 of the License, or
  114.11 + *   (at your option) any later version.
  114.12 + *
  114.13 + *   This program is distributed in the hope that it will be useful,
  114.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  114.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  114.16 + *   GNU General Public License for more details.
  114.17 + *
  114.18 + *   You should have received a copy of the GNU General Public License
  114.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  114.20 + */
  114.21 +
  114.22 +package test;
  114.23 +
  114.24 +import org.sonews.util.StringTemplate;
  114.25 +
  114.26 +/**
  114.27 + * Tests the StringTemplate class.
  114.28 + * @author Christian Lins
  114.29 + * @since sonews/0.5.0
  114.30 + * @see org.sonews.util.StringTemplate
  114.31 + */
  114.32 +public class StringTemplateTest 
  114.33 +{
  114.34 +
  114.35 +  public static void main(String[] args)
  114.36 +  {
  114.37 +    StringTemplate templ 
  114.38 +      = new StringTemplate("SELECT %row FROM %table WHERE %row = ich");
  114.39 +    
  114.40 +    templ.set("row", "name");
  114.41 +    templ.set("table", "UserTable");
  114.42 +    
  114.43 +    System.out.println(templ.toString());
  114.44 +  }
  114.45 +
  114.46 +}
   115.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   115.2 +++ b/test/TestBench.java	Fri Jun 26 16:48:50 2009 +0200
   115.3 @@ -0,0 +1,98 @@
   115.4 +/*
   115.5 + *   StarOffice News Server
   115.6 + *   see AUTHORS for the list of contributors
   115.7 + *
   115.8 + *   This program is free software: you can redistribute it and/or modify
   115.9 + *   it under the terms of the GNU General Public License as published by
  115.10 + *   the Free Software Foundation, either version 3 of the License, or
  115.11 + *   (at your option) any later version.
  115.12 + *
  115.13 + *   This program is distributed in the hope that it will be useful,
  115.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  115.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  115.16 + *   GNU General Public License for more details.
  115.17 + *
  115.18 + *   You should have received a copy of the GNU General Public License
  115.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  115.20 + */
  115.21 +
  115.22 +package test;
  115.23 +
  115.24 +import test.command.HelloQuitTest;
  115.25 +import test.command.ArticleTest;
  115.26 +import java.util.LinkedList;
  115.27 +import java.util.List;
  115.28 +import test.command.CapabilitiesTest;
  115.29 +import test.command.GroupTest;
  115.30 +import test.command.ListGroupTests;
  115.31 +import test.command.ListTest;
  115.32 +import test.command.NewGroupsTest;
  115.33 +import test.command.NextTest;
  115.34 +import test.command.OverTest;
  115.35 +import test.command.PostTest;
  115.36 +
  115.37 +/**
  115.38 + * Run this class to perform a full test.
  115.39 + * @author Christian Lins
  115.40 + * @since sonews/0.5.0
  115.41 + */
  115.42 +public final class TestBench 
  115.43 +{
  115.44 +  
  115.45 +  public static void main(String[] args)
  115.46 +  {
  115.47 +    System.out.println("TestBench for NNTP (RFC3799) based servers ");
  115.48 +    if(args.length < 1)
  115.49 +    {
  115.50 +      System.out.println("Usage: TestBench <host>[:port]");
  115.51 +      return;
  115.52 +    }
  115.53 +    
  115.54 +    String[] hostport = args[0].split(":");
  115.55 +    String host = hostport[0];
  115.56 +    int    port = 119;
  115.57 +    if(hostport.length == 2)
  115.58 +    {
  115.59 +      port = Integer.parseInt(hostport[1]);
  115.60 +    }
  115.61 +
  115.62 +    List<AbstractTest> tests = new LinkedList<AbstractTest>();
  115.63 +    
  115.64 +    // Add tests to perform
  115.65 +    tests.add(new HelloQuitTest());
  115.66 +    tests.add(new PostTest());    // Post before Article
  115.67 +    tests.add(new ArticleTest());
  115.68 +    tests.add(new CapabilitiesTest());
  115.69 +    tests.add(new GroupTest());
  115.70 +    tests.add(new ListGroupTests());
  115.71 +    tests.add(new ListTest());
  115.72 +    tests.add(new NewGroupsTest());
  115.73 +    tests.add(new NextTest());
  115.74 +    tests.add(new OverTest());
  115.75 +    
  115.76 +    // Perform all tests
  115.77 +    for(AbstractTest test : tests)
  115.78 +    {
  115.79 +      try
  115.80 +      {
  115.81 +        test.connect(host, port);
  115.82 +        int result = test.runTest();
  115.83 +        System.out.print(test.getClass().getName() + " finished with exit code " + result + "\t => ");
  115.84 +        if(result == 0)
  115.85 +        {
  115.86 +          System.out.println("SUCCESS");
  115.87 +        }
  115.88 +        else
  115.89 +        {
  115.90 +          System.out.println("FAILURE");
  115.91 +        }
  115.92 +      }
  115.93 +      catch(Exception ex)
  115.94 +      {
  115.95 +        System.out.println("Test " + test.getClass().getName() + " failed: " + ex.getLocalizedMessage());
  115.96 +        ex.printStackTrace();
  115.97 +      }
  115.98 +    }
  115.99 +  }
 115.100 +  
 115.101 +}
   116.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   116.2 +++ b/test/command/ArticleTest.java	Fri Jun 26 16:48:50 2009 +0200
   116.3 @@ -0,0 +1,90 @@
   116.4 +/*
   116.5 + *   StarOffice News Server
   116.6 + *   see AUTHORS for the list of contributors
   116.7 + *
   116.8 + *   This program is free software: you can redistribute it and/or modify
   116.9 + *   it under the terms of the GNU General Public License as published by
  116.10 + *   the Free Software Foundation, either version 3 of the License, or
  116.11 + *   (at your option) any later version.
  116.12 + *
  116.13 + *   This program is distributed in the hope that it will be useful,
  116.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  116.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  116.16 + *   GNU General Public License for more details.
  116.17 + *
  116.18 + *   You should have received a copy of the GNU General Public License
  116.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  116.20 + */
  116.21 +
  116.22 +package test.command;
  116.23 +
  116.24 +import test.AbstractTest;
  116.25 +
  116.26 +/**
  116.27 + * Tests the ARTICLE command.
  116.28 + * @author Christian Lins
  116.29 + * @since sonews/0.5.0
  116.30 + */
  116.31 +public class ArticleTest extends AbstractTest
  116.32 +{
  116.33 +  
  116.34 +  @Override
  116.35 +  public int runTest()
  116.36 +    throws Exception
  116.37 +  {
  116.38 +    String line = readln();
  116.39 +    if(!line.startsWith("200 "))
  116.40 +    {
  116.41 +      return 1;
  116.42 +    }
  116.43 +    
  116.44 +    // Select a group (we assume that local.test is existing)
  116.45 +    println("GROUP local.test");
  116.46 +    line = readln();
  116.47 +    if(!line.startsWith("211 "))
  116.48 +    {
  116.49 +      println("GROUP test");
  116.50 +      line = readln();
  116.51 +      if(!line.startsWith("211 "))
  116.52 +      {
  116.53 +        return 3;
  116.54 +      }
  116.55 +    }
  116.56 +    
  116.57 +    // Retrieve the first article
  116.58 +    println("ARTICLE " + line.split(" ")[2]);
  116.59 +    line = readln();
  116.60 +    if(!line.startsWith("220 "))
  116.61 +    {
  116.62 +      return 4;
  116.63 +    }
  116.64 +    
  116.65 +    while(!line.equals("."))
  116.66 +    {
  116.67 +      line = readln(); 
  116.68 +    }
  116.69 +    
  116.70 +    // Retrieve currently selected article (without a parameter number!)
  116.71 +    println("ARTICLE");
  116.72 +    line = readln();
  116.73 +    if(!line.startsWith("220 "))
  116.74 +    {
  116.75 +      return 5;
  116.76 +    }
  116.77 +    
  116.78 +    while(!line.equals("."))
  116.79 +    {
  116.80 +      line = readln(); 
  116.81 +    }
  116.82 +    
  116.83 +    println("QUIT");
  116.84 +    line = readln();
  116.85 +    if(!line.startsWith("205 "))
  116.86 +    {
  116.87 +      return 2;
  116.88 +    }
  116.89 +    
  116.90 +    return 0;
  116.91 +  }
  116.92 +  
  116.93 +}
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/test/command/CapabilitiesTest.java	Fri Jun 26 16:48:50 2009 +0200
   117.3 @@ -0,0 +1,63 @@
   117.4 +/*
   117.5 + *   StarOffice News Server
   117.6 + *   see AUTHORS for the list of contributors
   117.7 + *
   117.8 + *   This program is free software: you can redistribute it and/or modify
   117.9 + *   it under the terms of the GNU General Public License as published by
  117.10 + *   the Free Software Foundation, either version 3 of the License, or
  117.11 + *   (at your option) any later version.
  117.12 + *
  117.13 + *   This program is distributed in the hope that it will be useful,
  117.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  117.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  117.16 + *   GNU General Public License for more details.
  117.17 + *
  117.18 + *   You should have received a copy of the GNU General Public License
  117.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  117.20 + */
  117.21 +
  117.22 +package test.command;
  117.23 +
  117.24 +import test.AbstractTest;
  117.25 +
  117.26 +/**
  117.27 + * Tests the CAPABILITIES command.
  117.28 + * @author Christian Lins
  117.29 + * @since sonews/0.5.0
  117.30 + */
  117.31 +public class CapabilitiesTest extends AbstractTest
  117.32 +{
  117.33 +
  117.34 +  @Override
  117.35 +  public int runTest()
  117.36 +    throws Exception
  117.37 +  {
  117.38 +    String line = readln();
  117.39 +    if(!line.startsWith("200 "))
  117.40 +    {
  117.41 +      return 1;
  117.42 +    }
  117.43 +    
  117.44 +    println("CAPABILITIES");
  117.45 +    line = readln();
  117.46 +    if(!line.startsWith("101"))
  117.47 +    {
  117.48 +      return 3;
  117.49 +    }
  117.50 +    
  117.51 +    while(!line.equals("."))
  117.52 +    {
  117.53 +      line = readln();
  117.54 +    }
  117.55 +    
  117.56 +    println("QUIT");
  117.57 +    line = readln();
  117.58 +    if(!line.startsWith("205 "))
  117.59 +    {
  117.60 +      return 2;
  117.61 +    }
  117.62 +    
  117.63 +    return 0;
  117.64 +  }
  117.65 +  
  117.66 +}
   118.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   118.2 +++ b/test/command/GroupTest.java	Fri Jun 26 16:48:50 2009 +0200
   118.3 @@ -0,0 +1,49 @@
   118.4 +/*
   118.5 + *   StarOffice News Server
   118.6 + *   see AUTHORS for the list of contributors
   118.7 + *
   118.8 + *   This program is free software: you can redistribute it and/or modify
   118.9 + *   it under the terms of the GNU General Public License as published by
  118.10 + *   the Free Software Foundation, either version 3 of the License, or
  118.11 + *   (at your option) any later version.
  118.12 + *
  118.13 + *   This program is distributed in the hope that it will be useful,
  118.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  118.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  118.16 + *   GNU General Public License for more details.
  118.17 + *
  118.18 + *   You should have received a copy of the GNU General Public License
  118.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  118.20 + */
  118.21 +
  118.22 +package test.command;
  118.23 +
  118.24 +import test.AbstractTest;
  118.25 +
  118.26 +/**
  118.27 + * Tests the GROUP command.
  118.28 + * @author Christian Lins
  118.29 + * @since sonews/0.5.0
  118.30 + */
  118.31 +public class GroupTest extends AbstractTest
  118.32 +{
  118.33 +
  118.34 +  @Override
  118.35 +  public int runTest()
  118.36 +    throws Exception
  118.37 +  {
  118.38 +    String line = readln();
  118.39 +    
  118.40 +    println("GROUP misc.test");
  118.41 +    line = readln();
  118.42 +    if(line.startsWith("211 "))
  118.43 +    {
  118.44 +      return 0;
  118.45 +    }
  118.46 +    else
  118.47 +    {
  118.48 +      return 1;
  118.49 +    }
  118.50 +  }
  118.51 +  
  118.52 +}
   119.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   119.2 +++ b/test/command/HelloQuitTest.java	Fri Jun 26 16:48:50 2009 +0200
   119.3 @@ -0,0 +1,47 @@
   119.4 +/*
   119.5 + *   StarOffice News Server
   119.6 + *   see AUTHORS for the list of contributors
   119.7 + *
   119.8 + *   This program is free software: you can redistribute it and/or modify
   119.9 + *   it under the terms of the GNU General Public License as published by
  119.10 + *   the Free Software Foundation, either version 3 of the License, or
  119.11 + *   (at your option) any later version.
  119.12 + *
  119.13 + *   This program is distributed in the hope that it will be useful,
  119.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  119.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  119.16 + *   GNU General Public License for more details.
  119.17 + *
  119.18 + *   You should have received a copy of the GNU General Public License
  119.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  119.20 + */
  119.21 +
  119.22 +package test.command;
  119.23 +
  119.24 +import test.AbstractTest;
  119.25 +
  119.26 +/**
  119.27 + * Test: connects to server, waits for initial hello and quits.
  119.28 + * @author Christian Lins
  119.29 + * @since sonews/0.5.0
  119.30 + */
  119.31 +public class HelloQuitTest extends AbstractTest
  119.32 +{
  119.33 +
  119.34 +  @Override
  119.35 +  public int runTest()
  119.36 +    throws Exception
  119.37 +  {
  119.38 +    String line = readln();
  119.39 +    if(!line.startsWith("200 "))
  119.40 +      return 1;
  119.41 +    
  119.42 +    println("QUIT");
  119.43 +    line = readln();
  119.44 +    if(!line.startsWith("205 "))
  119.45 +      return 2;
  119.46 +    
  119.47 +    return 0;
  119.48 +  }
  119.49 +  
  119.50 +}
   120.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   120.2 +++ b/test/command/ListGroupTests.java	Fri Jun 26 16:48:50 2009 +0200
   120.3 @@ -0,0 +1,38 @@
   120.4 +/*
   120.5 + *   StarOffice News Server
   120.6 + *   see AUTHORS for the list of contributors
   120.7 + *
   120.8 + *   This program is free software: you can redistribute it and/or modify
   120.9 + *   it under the terms of the GNU General Public License as published by
  120.10 + *   the Free Software Foundation, either version 3 of the License, or
  120.11 + *   (at your option) any later version.
  120.12 + *
  120.13 + *   This program is distributed in the hope that it will be useful,
  120.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  120.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  120.16 + *   GNU General Public License for more details.
  120.17 + *
  120.18 + *   You should have received a copy of the GNU General Public License
  120.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  120.20 + */
  120.21 +
  120.22 +package test.command;
  120.23 +
  120.24 +import test.AbstractTest;
  120.25 +
  120.26 +/**
  120.27 + * Tests the LISTGROUP command.
  120.28 + * @author Christian Lins
  120.29 + * @since sonews/0.5.0
  120.30 + */
  120.31 +public class ListGroupTests extends AbstractTest
  120.32 +{
  120.33 +
  120.34 +  @Override
  120.35 +  public int runTest()
  120.36 +    throws Exception
  120.37 +  {
  120.38 +    return 1;
  120.39 +  }
  120.40 +  
  120.41 +}
   121.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.2 +++ b/test/command/ListTest.java	Fri Jun 26 16:48:50 2009 +0200
   121.3 @@ -0,0 +1,49 @@
   121.4 +/*
   121.5 + *   StarOffice News Server
   121.6 + *   see AUTHORS for the list of contributors
   121.7 + *
   121.8 + *   This program is free software: you can redistribute it and/or modify
   121.9 + *   it under the terms of the GNU General Public License as published by
  121.10 + *   the Free Software Foundation, either version 3 of the License, or
  121.11 + *   (at your option) any later version.
  121.12 + *
  121.13 + *   This program is distributed in the hope that it will be useful,
  121.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  121.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  121.16 + *   GNU General Public License for more details.
  121.17 + *
  121.18 + *   You should have received a copy of the GNU General Public License
  121.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  121.20 + */
  121.21 +
  121.22 +package test.command;
  121.23 +
  121.24 +import test.AbstractTest;
  121.25 +
  121.26 +/**
  121.27 + * Blackbox Test testing the LIST command
  121.28 + * @author Christian Lins
  121.29 + * @since sonews/0.5.0
  121.30 + */
  121.31 +public class ListTest extends AbstractTest
  121.32 +{
  121.33 +  
  121.34 +  @Override
  121.35 +  public int runTest()
  121.36 +    throws Exception
  121.37 +  {
  121.38 +    println("LIST OVERVIEW.FMT");
  121.39 +    String line = readln();
  121.40 +    if(line.startsWith("215 "))
  121.41 +    {
  121.42 +      while(!line.equals("."))
  121.43 +      {
  121.44 +        line = readln();
  121.45 +      }
  121.46 +      return 0;
  121.47 +    }
  121.48 +    else
  121.49 +      return 1;
  121.50 +  }
  121.51 +  
  121.52 +}
   122.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.2 +++ b/test/command/NewGroupsTest.java	Fri Jun 26 16:48:50 2009 +0200
   122.3 @@ -0,0 +1,37 @@
   122.4 +/*
   122.5 + *   StarOffice News Server
   122.6 + *   see AUTHORS for the list of contributors
   122.7 + *
   122.8 + *   This program is free software: you can redistribute it and/or modify
   122.9 + *   it under the terms of the GNU General Public License as published by
  122.10 + *   the Free Software Foundation, either version 3 of the License, or
  122.11 + *   (at your option) any later version.
  122.12 + *
  122.13 + *   This program is distributed in the hope that it will be useful,
  122.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  122.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  122.16 + *   GNU General Public License for more details.
  122.17 + *
  122.18 + *   You should have received a copy of the GNU General Public License
  122.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  122.20 + */
  122.21 +package test.command;
  122.22 +
  122.23 +import test.AbstractTest;
  122.24 +
  122.25 +/**
  122.26 + * Tests the NEWGROUPS command.
  122.27 + * @author Christian Lins
  122.28 + * @since sonews/0.5.0
  122.29 + */
  122.30 +public class NewGroupsTest extends AbstractTest
  122.31 +{
  122.32 +
  122.33 +  @Override
  122.34 +  public int runTest()
  122.35 +    throws Exception
  122.36 +  {
  122.37 +    return 1;
  122.38 +  }
  122.39 +  
  122.40 +}
   123.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   123.2 +++ b/test/command/NextTest.java	Fri Jun 26 16:48:50 2009 +0200
   123.3 @@ -0,0 +1,38 @@
   123.4 +/*
   123.5 + *   StarOffice News Server
   123.6 + *   see AUTHORS for the list of contributors
   123.7 + *
   123.8 + *   This program is free software: you can redistribute it and/or modify
   123.9 + *   it under the terms of the GNU General Public License as published by
  123.10 + *   the Free Software Foundation, either version 3 of the License, or
  123.11 + *   (at your option) any later version.
  123.12 + *
  123.13 + *   This program is distributed in the hope that it will be useful,
  123.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  123.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  123.16 + *   GNU General Public License for more details.
  123.17 + *
  123.18 + *   You should have received a copy of the GNU General Public License
  123.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  123.20 + */
  123.21 +
  123.22 +package test.command;
  123.23 +
  123.24 +import test.AbstractTest;
  123.25 +
  123.26 +/**
  123.27 + * Tests the NEXT command.
  123.28 + * @author Christian Lins
  123.29 + * @since sonews/0.5.0
  123.30 + */
  123.31 +public class NextTest extends AbstractTest
  123.32 +{
  123.33 +  
  123.34 +  @Override
  123.35 +  public int runTest()
  123.36 +    throws Exception
  123.37 +  {
  123.38 +    return 1;
  123.39 +  }
  123.40 +
  123.41 +}
   124.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   124.2 +++ b/test/command/OverTest.java	Fri Jun 26 16:48:50 2009 +0200
   124.3 @@ -0,0 +1,135 @@
   124.4 +/*
   124.5 + *   StarOffice News Server
   124.6 + *   see AUTHORS for the list of contributors
   124.7 + *
   124.8 + *   This program is free software: you can redistribute it and/or modify
   124.9 + *   it under the terms of the GNU General Public License as published by
  124.10 + *   the Free Software Foundation, either version 3 of the License, or
  124.11 + *   (at your option) any later version.
  124.12 + *
  124.13 + *   This program is distributed in the hope that it will be useful,
  124.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  124.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  124.16 + *   GNU General Public License for more details.
  124.17 + *
  124.18 + *   You should have received a copy of the GNU General Public License
  124.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  124.20 + */
  124.21 +
  124.22 +package test.command;
  124.23 +
  124.24 +import java.text.SimpleDateFormat;
  124.25 +import java.util.ArrayList;
  124.26 +import java.util.List;
  124.27 +import test.AbstractTest;
  124.28 +
  124.29 +/**
  124.30 + * Tests the OVER/XOVER command.
  124.31 + * @author Christian Lins
  124.32 + * @since sonews/0.5.0
  124.33 + */
  124.34 +public class OverTest extends AbstractTest
  124.35 +{
  124.36 +
  124.37 +  @Override
  124.38 +  public int runTest()
  124.39 +    throws Exception
  124.40 +  {
  124.41 +    // Send HELLO to server
  124.42 +    String line = readln();
  124.43 +    if(!line.startsWith("200 "))
  124.44 +    {
  124.45 +      return 1;
  124.46 +    }
  124.47 +
  124.48 +    // Determine available groups
  124.49 +    println("LIST");
  124.50 +    line = readln();
  124.51 +    if(!line.startsWith("215 "))
  124.52 +    {
  124.53 +      return 2;
  124.54 +    }
  124.55 +
  124.56 +    List<String> groups = new ArrayList<String>();
  124.57 +    line = readln();
  124.58 +    for(;;)
  124.59 +    {
  124.60 +      if(line.equals("."))
  124.61 +      {
  124.62 +        break;
  124.63 +      }
  124.64 +      else
  124.65 +      {
  124.66 +        groups.add(line);
  124.67 +        line = readln();
  124.68 +      }
  124.69 +    }
  124.70 +
  124.71 +    if(groups.size() <= 0)
  124.72 +    {
  124.73 +      return 3;
  124.74 +    }
  124.75 +
  124.76 +    // Test OVER command on every group
  124.77 +    for(String group : groups)
  124.78 +    {
  124.79 +      String groupName = group.split(" ")[0];
  124.80 +      println("GROUP " + groupName);
  124.81 +      line = readln();
  124.82 +      if(!line.startsWith("211 "))
  124.83 +      {
  124.84 +        return 4;
  124.85 +      }
  124.86 +
  124.87 +      String[] lineToks = line.split(" ");
  124.88 +      println("XOVER " + lineToks[2] + "-" + lineToks[3]);
  124.89 +      line = readln();
  124.90 +      if(line.startsWith("423"))
  124.91 +      {
  124.92 +        continue;
  124.93 +      }
  124.94 +      else if(!line.startsWith("224 "))
  124.95 +      {
  124.96 +        return 5;
  124.97 +      }
  124.98 +      
  124.99 +      line = readln();
 124.100 +      for(;;)
 124.101 +      {
 124.102 +        if(line == null)
 124.103 +        {
 124.104 +          return 7;
 124.105 +        }
 124.106 +        else if(line.equals("."))
 124.107 +        {
 124.108 +          break;
 124.109 +        }
 124.110 +
 124.111 +        // Validate the line
 124.112 +        lineToks = line.split("\t");
 124.113 +        if(lineToks.length < 6)
 124.114 +        {
 124.115 +          return 6;
 124.116 +        }
 124.117 +        else
 124.118 +        {
 124.119 +          Integer.parseInt(lineToks[0]);
 124.120 +
 124.121 +          //SimpleDateFormat sdf = new SimpleDateFormat(group)
 124.122 +
 124.123 +          if(!lineToks[4].startsWith("<") && !lineToks[4].endsWith(">"))
 124.124 +          {
 124.125 +            log.println("Invalid Message-ID: " + lineToks[1]);
 124.126 +            log.flush();
 124.127 +            return 8;
 124.128 +          }
 124.129 +        }
 124.130 +
 124.131 +        line = readln();
 124.132 +      }
 124.133 +    }
 124.134 +    
 124.135 +    return 0;
 124.136 +  }
 124.137 +  
 124.138 +}
   125.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   125.2 +++ b/test/command/PostTest.java	Fri Jun 26 16:48:50 2009 +0200
   125.3 @@ -0,0 +1,82 @@
   125.4 +/*
   125.5 + *   StarOffice News Server
   125.6 + *   see AUTHORS for the list of contributors
   125.7 + *
   125.8 + *   This program is free software: you can redistribute it and/or modify
   125.9 + *   it under the terms of the GNU General Public License as published by
  125.10 + *   the Free Software Foundation, either version 3 of the License, or
  125.11 + *   (at your option) any later version.
  125.12 + *
  125.13 + *   This program is distributed in the hope that it will be useful,
  125.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  125.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  125.16 + *   GNU General Public License for more details.
  125.17 + *
  125.18 + *   You should have received a copy of the GNU General Public License
  125.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  125.20 + */
  125.21 +
  125.22 +package test.command;
  125.23 +
  125.24 +import test.AbstractTest;
  125.25 +
  125.26 +/**
  125.27 + * Tests the POST command.
  125.28 + * @author Christian Lins
  125.29 + * @since sonews/0.5.0
  125.30 + */
  125.31 +public class PostTest extends AbstractTest
  125.32 +{
  125.33 +  
  125.34 +  @Override
  125.35 +  public int runTest()
  125.36 +    throws Exception
  125.37 +  {
  125.38 +    String line = readln();
  125.39 +    if(!line.startsWith("200 "))
  125.40 +    {
  125.41 +      return 1;
  125.42 +    }
  125.43 +    
  125.44 +    println("POST");
  125.45 +    line = readln();
  125.46 +    if(!line.startsWith("340 "))
  125.47 +    {
  125.48 +      return 1;
  125.49 +    }
  125.50 +    
  125.51 +    // Post a sample article
  125.52 +    postArticle("local.test");
  125.53 +    line = readln();
  125.54 +    if(line.startsWith("441 "))
  125.55 +    {
  125.56 +      println("POST");
  125.57 +      line = readln();
  125.58 +      if(!line.startsWith("340 "))
  125.59 +      {
  125.60 +        return 2;
  125.61 +      }
  125.62 +      
  125.63 +      postArticle("test");
  125.64 +      line = readln();
  125.65 +    }
  125.66 +
  125.67 +    if(!line.startsWith("240 "))
  125.68 +    {
  125.69 +      return 3;
  125.70 +    }
  125.71 +
  125.72 +    return 0;
  125.73 +  }
  125.74 +  
  125.75 +  private void postArticle(String toGroup)
  125.76 +  {
  125.77 +    println("Subject: A simple test mail");
  125.78 +    println("From: NNTP TestBench <testbench@sonews.org>");
  125.79 +    println("Newsgroups: " + toGroup);
  125.80 +    println("");
  125.81 +    println("Hello World!");
  125.82 +    println(".");
  125.83 +  }
  125.84 +
  125.85 +}
   126.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   126.2 +++ b/test/command/package.html	Fri Jun 26 16:48:50 2009 +0200
   126.3 @@ -0,0 +1,1 @@
   126.4 +Contains conformance tests for various NNTP commands.
   126.5 \ No newline at end of file
   127.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   127.2 +++ b/test/package.html	Fri Jun 26 16:48:50 2009 +0200
   127.3 @@ -0,0 +1,1 @@
   127.4 +Root package for test classes.
   127.5 \ No newline at end of file
   128.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   128.2 +++ b/test/unit/DaemonTests.java	Fri Jun 26 16:48:50 2009 +0200
   128.3 @@ -0,0 +1,38 @@
   128.4 +/*
   128.5 + *   SONEWS News Server
   128.6 + *   see AUTHORS for the list of contributors
   128.7 + *
   128.8 + *   This program is free software: you can redistribute it and/or modify
   128.9 + *   it under the terms of the GNU General Public License as published by
  128.10 + *   the Free Software Foundation, either version 3 of the License, or
  128.11 + *   (at your option) any later version.
  128.12 + *
  128.13 + *   This program is distributed in the hope that it will be useful,
  128.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  128.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  128.16 + *   GNU General Public License for more details.
  128.17 + *
  128.18 + *   You should have received a copy of the GNU General Public License
  128.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  128.20 + */
  128.21 +
  128.22 +package test.unit;
  128.23 +
  128.24 +import junit.textui.TestRunner;
  128.25 +import test.unit.daemon.NNTPConnectionTest;
  128.26 +
  128.27 +/**
  128.28 + * Tests the org.sonews.daemon package classes.
  128.29 + * @author Christian Lins
  128.30 + * @since sonews/0.5.0
  128.31 + */
  128.32 +public class DaemonTests 
  128.33 +{
  128.34 +
  128.35 +  public static void main(String[] args)
  128.36 +  {
  128.37 +    System.out.println("NNTPConnectionTest");
  128.38 +    TestRunner.run(NNTPConnectionTest.class);
  128.39 +  }
  128.40 +
  128.41 +}
   129.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   129.2 +++ b/test/unit/UtilTests.java	Fri Jun 26 16:48:50 2009 +0200
   129.3 @@ -0,0 +1,47 @@
   129.4 +/*
   129.5 + *   StarOffice News Server
   129.6 + *   see AUTHORS for the list of contributors
   129.7 + *
   129.8 + *   This program is free software: you can redistribute it and/or modify
   129.9 + *   it under the terms of the GNU General Public License as published by
  129.10 + *   the Free Software Foundation, either version 3 of the License, or
  129.11 + *   (at your option) any later version.
  129.12 + *
  129.13 + *   This program is distributed in the hope that it will be useful,
  129.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  129.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  129.16 + *   GNU General Public License for more details.
  129.17 + *
  129.18 + *   You should have received a copy of the GNU General Public License
  129.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  129.20 + */
  129.21 +
  129.22 +package test.unit;
  129.23 +
  129.24 +import junit.textui.TestRunner;
  129.25 +import test.unit.util.ResourceTest;
  129.26 +import test.unit.util.StringTemplateTest;
  129.27 +import test.unit.util.TimeoutMapTest;
  129.28 +
  129.29 +
  129.30 +/**
  129.31 + * Tests classes of package org.sonews.util.
  129.32 + * @author Christian Lins
  129.33 + * @since sonews/0.5.0
  129.34 + */
  129.35 +public class UtilTests
  129.36 +{
  129.37 +  
  129.38 +  public static void main(String[] args)
  129.39 +  {
  129.40 +    System.out.println("StringTemplateTest");
  129.41 +    TestRunner.run(StringTemplateTest.class);
  129.42 +    
  129.43 +    System.out.println("TimeoutMapTest");
  129.44 +    TestRunner.run(TimeoutMapTest.class);
  129.45 +    
  129.46 +    System.out.println("ResourceTest");
  129.47 +    TestRunner.run(ResourceTest.class);
  129.48 +  }
  129.49 +  
  129.50 +}
   130.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   130.2 +++ b/test/unit/daemon/NNTPConnectionTest.java	Fri Jun 26 16:48:50 2009 +0200
   130.3 @@ -0,0 +1,122 @@
   130.4 +/*
   130.5 + *   SONEWS News Server
   130.6 + *   see AUTHORS for the list of contributors
   130.7 + *
   130.8 + *   This program is free software: you can redistribute it and/or modify
   130.9 + *   it under the terms of the GNU General Public License as published by
  130.10 + *   the Free Software Foundation, either version 3 of the License, or
  130.11 + *   (at your option) any later version.
  130.12 + *
  130.13 + *   This program is distributed in the hope that it will be useful,
  130.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  130.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  130.16 + *   GNU General Public License for more details.
  130.17 + *
  130.18 + *   You should have received a copy of the GNU General Public License
  130.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  130.20 + */
  130.21 +
  130.22 +package test.unit.daemon;
  130.23 +
  130.24 +import java.io.IOException;
  130.25 +import java.lang.reflect.InvocationTargetException;
  130.26 +import java.lang.reflect.Method;
  130.27 +import java.nio.channels.SocketChannel;
  130.28 +import junit.framework.TestCase;
  130.29 +import org.sonews.daemon.NNTPConnection;
  130.30 +import org.sonews.daemon.command.ArticleCommand;
  130.31 +import org.sonews.daemon.command.CapabilitiesCommand;
  130.32 +import org.sonews.daemon.command.GroupCommand;
  130.33 +import org.sonews.daemon.command.UnsupportedCommand;
  130.34 +
  130.35 +/**
  130.36 + * Unit test for class NNTPConnection.
  130.37 + * @author Christian Lins
  130.38 + * @since sonews/0.5.0
  130.39 + */
  130.40 +public class NNTPConnectionTest extends TestCase
  130.41 +{
  130.42 +
  130.43 +  public void testLineReceived()
  130.44 +    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
  130.45 +  {
  130.46 +    NNTPConnection conn = null;
  130.47 +    
  130.48 +    try
  130.49 +    {
  130.50 +      try
  130.51 +      {
  130.52 +        conn = new NNTPConnection(null);
  130.53 +        fail("Should have raised an IllegalArgumentException");
  130.54 +      }
  130.55 +      catch(IOException ex) {ex.printStackTrace();}
  130.56 +    }
  130.57 +    catch(IllegalArgumentException ex){}
  130.58 +    
  130.59 +    try
  130.60 +    {
  130.61 +      conn = new NNTPConnection(SocketChannel.open());
  130.62 +    }
  130.63 +    catch(IOException ex)
  130.64 +    {
  130.65 +      ex.printStackTrace();
  130.66 +    }
  130.67 +    
  130.68 +    assertNotNull(conn);
  130.69 +    
  130.70 +    // Make interesting methods accessible
  130.71 +    Class  clazz           = conn.getClass();
  130.72 +    Method methTryReadLock = clazz.getDeclaredMethod("tryReadLock", null);
  130.73 +    methTryReadLock.setAccessible(true);
  130.74 +    Method methLineReceived = clazz.getDeclaredMethod("lineReceived", new byte[0].getClass());
  130.75 +    methLineReceived.setAccessible(true);
  130.76 +    
  130.77 +    try
  130.78 +    {
  130.79 +      // conn.lineReceived(null);
  130.80 +      methLineReceived.invoke(conn, null);
  130.81 +      fail("Should have raised an IllegalArgumentException");
  130.82 +    }
  130.83 +    catch(IllegalArgumentException ex){}
  130.84 +    
  130.85 +    try
  130.86 +    {
  130.87 +      // conn.lineReceived(new byte[0]);
  130.88 +      methLineReceived.invoke(conn, new byte[0]);
  130.89 +      fail("Should have raised IllegalStateException");
  130.90 +    }
  130.91 +    catch(InvocationTargetException ex){}
  130.92 +    
  130.93 +    boolean tryReadLock = (Boolean)methTryReadLock.invoke(conn, null);
  130.94 +    assertTrue(tryReadLock);
  130.95 +    
  130.96 +    // conn.lineReceived("MODE READER".getBytes());
  130.97 +    methLineReceived.invoke(conn, "MODE READER".getBytes());
  130.98 +    
  130.99 +    // conn.lineReceived("sdkfsdjnfksjfdng ksdf gksjdfngk nskfng ksndfg ".getBytes());
 130.100 +    methLineReceived.invoke(conn, "sdkfsdjnfksjfdng ksdf ksndfg ".getBytes());
 130.101 +    
 130.102 +    // conn.lineReceived(new byte[1024]); // Too long
 130.103 +    methLineReceived.invoke(conn, new byte[1024]);
 130.104 +    
 130.105 +    Method mpcmdl = conn.getClass().getDeclaredMethod("parseCommandLine", String.class);
 130.106 +    mpcmdl.setAccessible(true);
 130.107 +
 130.108 +    Object result = mpcmdl.invoke(conn, "");
 130.109 +    assertNotNull(result);
 130.110 +    assertTrue(result instanceof UnsupportedCommand);
 130.111 +    
 130.112 +    result = mpcmdl.invoke(conn, "aRtiCle");
 130.113 +    assertNotNull(result);
 130.114 +    assertTrue(result instanceof ArticleCommand);
 130.115 +    
 130.116 +    result = mpcmdl.invoke(conn, "capAbilItIEs");
 130.117 +    assertNotNull(result);
 130.118 +    assertTrue(result instanceof CapabilitiesCommand);
 130.119 +    
 130.120 +    result = mpcmdl.invoke(conn, "grOUp");
 130.121 +    assertNotNull(result);
 130.122 +    assertTrue(result instanceof GroupCommand);
 130.123 +  }
 130.124 +  
 130.125 +}
   131.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   131.2 +++ b/test/unit/daemon/package.html	Fri Jun 26 16:48:50 2009 +0200
   131.3 @@ -0,0 +1,1 @@
   131.4 +Contains Unittests for the org.sonews.daemon package.
   131.5 \ No newline at end of file
   132.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   132.2 +++ b/test/unit/package.html	Fri Jun 26 16:48:50 2009 +0200
   132.3 @@ -0,0 +1,1 @@
   132.4 +Root package for Unittest classes.
   132.5 \ No newline at end of file
   133.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   133.2 +++ b/test/unit/util/ResourceTest.java	Fri Jun 26 16:48:50 2009 +0200
   133.3 @@ -0,0 +1,80 @@
   133.4 +/*
   133.5 + *   SONEWS News Server
   133.6 + *   see AUTHORS for the list of contributors
   133.7 + *
   133.8 + *   This program is free software: you can redistribute it and/or modify
   133.9 + *   it under the terms of the GNU General Public License as published by
  133.10 + *   the Free Software Foundation, either version 3 of the License, or
  133.11 + *   (at your option) any later version.
  133.12 + *
  133.13 + *   This program is distributed in the hope that it will be useful,
  133.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  133.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  133.16 + *   GNU General Public License for more details.
  133.17 + *
  133.18 + *   You should have received a copy of the GNU General Public License
  133.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  133.20 + */
  133.21 +
  133.22 +package test.unit.util;
  133.23 +
  133.24 +import junit.framework.TestCase;
  133.25 +import org.sonews.util.io.Resource;
  133.26 +
  133.27 +/**
  133.28 + * Unit test for class org.sonews.util.io.Resource.
  133.29 + * @author Christian Lins
  133.30 + * @see org.sonews.util.io.Resource
  133.31 + * @since sonews/0.5.0
  133.32 + */
  133.33 +public class ResourceTest extends TestCase
  133.34 +{
  133.35 +
  133.36 +  public void testGetAsURL()
  133.37 +  {
  133.38 +    Object url;
  133.39 +    
  133.40 +    url = Resource.getAsURL(null);
  133.41 +    assertNull(url);
  133.42 +    
  133.43 +    url = Resource.getAsURL("this is absolutely bullshit");
  133.44 +    assertNull(url);
  133.45 +    
  133.46 +    // This file should exist
  133.47 +    url = Resource.getAsURL("org/sonews/daemon/Main.class");
  133.48 +    assertNotNull(url);
  133.49 +  }
  133.50 +  
  133.51 +  public void testGetAsStream()
  133.52 +  {
  133.53 +    Object stream;
  133.54 +    
  133.55 +    stream = Resource.getAsStream(null);
  133.56 +    assertNull(stream);
  133.57 +    
  133.58 +    stream = Resource.getAsStream("this is bullshit");
  133.59 +    assertNull(stream);
  133.60 +    
  133.61 +    stream = Resource.getAsStream("org/sonews/daemon/Main.class");
  133.62 +    assertNotNull(stream);
  133.63 +  }
  133.64 +  
  133.65 +  public void testGetAsString()
  133.66 +  {
  133.67 +    String str;
  133.68 +    
  133.69 +    str = Resource.getAsString(null, true);
  133.70 +    assertNull(str);
  133.71 +    
  133.72 +    str = Resource.getAsString("this is bullshit", true);
  133.73 +    assertNull(str);
  133.74 +    
  133.75 +    str = Resource.getAsString("org/sonews/daemon/Main.class", true);
  133.76 +    assertNotNull(str);
  133.77 +    
  133.78 +    str = Resource.getAsString("org/sonews/daemon/Main.class", false);
  133.79 +    assertNotNull(str);
  133.80 +    assertEquals(str.indexOf("\n"), -1);
  133.81 +  }
  133.82 +  
  133.83 +}
   134.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   134.2 +++ b/test/unit/util/StringTemplateTest.java	Fri Jun 26 16:48:50 2009 +0200
   134.3 @@ -0,0 +1,91 @@
   134.4 +/*
   134.5 + *   SONEWS News Server
   134.6 + *   see AUTHORS for the list of contributors
   134.7 + *
   134.8 + *   This program is free software: you can redistribute it and/or modify
   134.9 + *   it under the terms of the GNU General Public License as published by
  134.10 + *   the Free Software Foundation, either version 3 of the License, or
  134.11 + *   (at your option) any later version.
  134.12 + *
  134.13 + *   This program is distributed in the hope that it will be useful,
  134.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  134.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  134.16 + *   GNU General Public License for more details.
  134.17 + *
  134.18 + *   You should have received a copy of the GNU General Public License
  134.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  134.20 + */
  134.21 +
  134.22 +package test.unit.util;
  134.23 +
  134.24 +import junit.framework.TestCase;
  134.25 +import org.sonews.util.StringTemplate;
  134.26 +
  134.27 +/**
  134.28 + * Unit test for class org.sonews.util.StringTemplate.
  134.29 + * @author Christian Lins 
  134.30 + * @see org.sonews.util.StringTemplate
  134.31 + * @since sonews/0.5.0
  134.32 + */
  134.33 +public class StringTemplateTest extends TestCase
  134.34 +{
  134.35 +
  134.36 +  private static final String template = "Hello %WORLD and others!";
  134.37 +  
  134.38 +  public StringTemplateTest()
  134.39 +  {
  134.40 +    super("StringTemplateTest");
  134.41 +  }
  134.42 +
  134.43 +  public void testCtor()
  134.44 +  {
  134.45 +    StringTemplate st;
  134.46 +    
  134.47 +    try
  134.48 +    {
  134.49 +      st = new StringTemplate(null);
  134.50 +      fail("Should have raised an IllegalArgumentException");
  134.51 +    }
  134.52 +    catch(IllegalArgumentException ex) {}
  134.53 +      
  134.54 +    st = new StringTemplate(template);
  134.55 +    assertNotNull(st);
  134.56 +    
  134.57 +    try
  134.58 +    {
  134.59 +      st = new StringTemplate(template, null);
  134.60 +      fail("Should have raised an IllegalArgumentException");
  134.61 +    }
  134.62 +    catch(IllegalArgumentException ex) {}
  134.63 +    
  134.64 +    st = new StringTemplate(template, "?");
  134.65 +    assertNotNull(st);
  134.66 +
  134.67 +    st = new StringTemplate(template, "%");
  134.68 +    assertNotNull(st);
  134.69 +  }
  134.70 +  
  134.71 +  public void testSetter()
  134.72 +  {
  134.73 +    StringTemplate st = new StringTemplate(template);
  134.74 +    
  134.75 +    try
  134.76 +    {
  134.77 +      st.set("WORLD", null);
  134.78 +      fail("Should have raised an IllegalArgumentException");
  134.79 +    }
  134.80 +    catch(IllegalArgumentException ex){}
  134.81 +    
  134.82 +    st.set("WORLD", "Universe");
  134.83 +  }
  134.84 +  
  134.85 +  public void testToString()
  134.86 +  {
  134.87 +    StringTemplate st = new StringTemplate(template);
  134.88 +    st.set("WORLD", "Universe");
  134.89 +    
  134.90 +    String result = st.toString();
  134.91 +    assertNotNull(result);
  134.92 +  }
  134.93 +  
  134.94 +}
   135.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.2 +++ b/test/unit/util/TimeoutMapTest.java	Fri Jun 26 16:48:50 2009 +0200
   135.3 @@ -0,0 +1,70 @@
   135.4 +/*
   135.5 + *   SONEWS News Server
   135.6 + *   see AUTHORS for the list of contributors
   135.7 + *
   135.8 + *   This program is free software: you can redistribute it and/or modify
   135.9 + *   it under the terms of the GNU General Public License as published by
  135.10 + *   the Free Software Foundation, either version 3 of the License, or
  135.11 + *   (at your option) any later version.
  135.12 + *
  135.13 + *   This program is distributed in the hope that it will be useful,
  135.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  135.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  135.16 + *   GNU General Public License for more details.
  135.17 + *
  135.18 + *   You should have received a copy of the GNU General Public License
  135.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  135.20 + */
  135.21 +
  135.22 +package test.unit.util;
  135.23 +
  135.24 +import junit.framework.TestCase;
  135.25 +import org.sonews.util.TimeoutMap;
  135.26 +
  135.27 +/**
  135.28 + * Unit test for class org.sonews.util.TimeoutMap.
  135.29 + * @author Christian Lins
  135.30 + * @since sonews/0.5.0
  135.31 + * @see org.sonews.util.TimeoutMap
  135.32 + */
  135.33 +public class TimeoutMapTest extends TestCase
  135.34 +{
  135.35 +
  135.36 +  public TimeoutMapTest()
  135.37 +  {
  135.38 +    super("TimeoutMapTest");
  135.39 +  }
  135.40 +  
  135.41 +  public void testTimeoutBehaviour()
  135.42 +  {
  135.43 +    TimeoutMap<String, Object> tm = new TimeoutMap<String, Object>(1000);
  135.44 +    Object testobj = new Object();
  135.45 +    
  135.46 +    tm.put("testkey", testobj);
  135.47 +    
  135.48 +    assertNotNull(tm.get("testkey"));
  135.49 +    assertTrue(tm.containsKey("testkey"));
  135.50 +    assertTrue(tm.contains(testobj));
  135.51 +    
  135.52 +    try
  135.53 +    {
  135.54 +      Thread.sleep(800);
  135.55 +    }
  135.56 +    catch(InterruptedException ex) { ex.printStackTrace(); }
  135.57 +    
  135.58 +    assertNotNull(tm.get("testkey"));
  135.59 +    assertTrue(tm.containsKey("testkey"));
  135.60 +    assertTrue(tm.contains(testobj));
  135.61 +    
  135.62 +    try
  135.63 +    {
  135.64 +      Thread.sleep(200);
  135.65 +    }
  135.66 +    catch(InterruptedException ex) { ex.printStackTrace(); }
  135.67 +    
  135.68 +    assertNull(tm.get("testkey"));
  135.69 +    assertFalse(tm.containsKey("testkey"));
  135.70 +    assertFalse(tm.contains(testobj));
  135.71 +  }
  135.72 +  
  135.73 +}
   136.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   136.2 +++ b/test/unit/util/package.html	Fri Jun 26 16:48:50 2009 +0200
   136.3 @@ -0,0 +1,1 @@
   136.4 +Contains Unittests for the package org.sonews.util.
   136.5 \ No newline at end of file
   137.1 --- a/trunk/AUTHORS	Tue Jan 20 10:21:03 2009 +0100
   137.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   137.3 @@ -1,26 +0,0 @@
   137.4 -AUTHORS & CREDITS
   137.5 -=================
   137.6 -
   137.7 -As most software applications "StarOffice News Server" is based on the work
   137.8 -of individuals or projects. These fine people contributing to the OpenSource
   137.9 -community are mentioned here:
  137.10 -
  137.11 -StarOffice News Server
  137.12 -----------------------
  137.13 -(c)Copyright 2009 by
  137.14 -  * Sun Microsystems, Inc.
  137.15 -  * Christian Lins <christian.lins@sun.com>
  137.16 -
  137.17 -based partly upon
  137.18 -
  137.19 -Neat NNTP Daemon (n3tpd)
  137.20 -------------------------
  137.21 -(c)Copyright 2007, 2008 by Christian Lins <christian.lins@web.de>
  137.22 -
  137.23 -based partly upon
  137.24 -
  137.25 -tnntpd
  137.26 -------
  137.27 -(c)Copyright 2003 by Dennis Schwerdel
  137.28 -
  137.29 -If you find someone missing here, please contact the project leader!
  137.30 \ No newline at end of file
   138.1 --- a/trunk/COPYING	Tue Jan 20 10:21:03 2009 +0100
   138.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   138.3 @@ -1,674 +0,0 @@
   138.4 -                    GNU GENERAL PUBLIC LICENSE
   138.5 -                       Version 3, 29 June 2007
   138.6 -
   138.7 - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
   138.8 - Everyone is permitted to copy and distribute verbatim copies
   138.9 - of this license document, but changing it is not allowed.
  138.10 -
  138.11 -                            Preamble
  138.12 -
  138.13 -  The GNU General Public License is a free, copyleft license for
  138.14 -software and other kinds of works.
  138.15 -
  138.16 -  The licenses for most software and other practical works are designed
  138.17 -to take away your freedom to share and change the works.  By contrast,
  138.18 -the GNU General Public License is intended to guarantee your freedom to
  138.19 -share and change all versions of a program--to make sure it remains free
  138.20 -software for all its users.  We, the Free Software Foundation, use the
  138.21 -GNU General Public License for most of our software; it applies also to
  138.22 -any other work released this way by its authors.  You can apply it to
  138.23 -your programs, too.
  138.24 -
  138.25 -  When we speak of free software, we are referring to freedom, not
  138.26 -price.  Our General Public Licenses are designed to make sure that you
  138.27 -have the freedom to distribute copies of free software (and charge for
  138.28 -them if you wish), that you receive source code or can get it if you
  138.29 -want it, that you can change the software or use pieces of it in new
  138.30 -free programs, and that you know you can do these things.
  138.31 -
  138.32 -  To protect your rights, we need to prevent others from denying you
  138.33 -these rights or asking you to surrender the rights.  Therefore, you have
  138.34 -certain responsibilities if you distribute copies of the software, or if
  138.35 -you modify it: responsibilities to respect the freedom of others.
  138.36 -
  138.37 -  For example, if you distribute copies of such a program, whether
  138.38 -gratis or for a fee, you must pass on to the recipients the same
  138.39 -freedoms that you received.  You must make sure that they, too, receive
  138.40 -or can get the source code.  And you must show them these terms so they
  138.41 -know their rights.
  138.42 -
  138.43 -  Developers that use the GNU GPL protect your rights with two steps:
  138.44 -(1) assert copyright on the software, and (2) offer you this License
  138.45 -giving you legal permission to copy, distribute and/or modify it.
  138.46 -
  138.47 -  For the developers' and authors' protection, the GPL clearly explains
  138.48 -that there is no warranty for this free software.  For both users' and
  138.49 -authors' sake, the GPL requires that modified versions be marked as
  138.50 -changed, so that their problems will not be attributed erroneously to
  138.51 -authors of previous versions.
  138.52 -
  138.53 -  Some devices are designed to deny users access to install or run
  138.54 -modified versions of the software inside them, although the manufacturer
  138.55 -can do so.  This is fundamentally incompatible with the aim of
  138.56 -protecting users' freedom to change the software.  The systematic
  138.57 -pattern of such abuse occurs in the area of products for individuals to
  138.58 -use, which is precisely where it is most unacceptable.  Therefore, we
  138.59 -have designed this version of the GPL to prohibit the practice for those
  138.60 -products.  If such problems arise substantially in other domains, we
  138.61 -stand ready to extend this provision to those domains in future versions
  138.62 -of the GPL, as needed to protect the freedom of users.
  138.63 -
  138.64 -  Finally, every program is threatened constantly by software patents.
  138.65 -States should not allow patents to restrict development and use of
  138.66 -software on general-purpose computers, but in those that do, we wish to
  138.67 -avoid the special danger that patents applied to a free program could
  138.68 -make it effectively proprietary.  To prevent this, the GPL assures that
  138.69 -patents cannot be used to render the program non-free.
  138.70 -
  138.71 -  The precise terms and conditions for copying, distribution and
  138.72 -modification follow.
  138.73 -
  138.74 -                       TERMS AND CONDITIONS
  138.75 -
  138.76 -  0. Definitions.
  138.77 -
  138.78 -  "This License" refers to version 3 of the GNU General Public License.
  138.79 -
  138.80 -  "Copyright" also means copyright-like laws that apply to other kinds of
  138.81 -works, such as semiconductor masks.
  138.82 -
  138.83 -  "The Program" refers to any copyrightable work licensed under this
  138.84 -License.  Each licensee is addressed as "you".  "Licensees" and
  138.85 -"recipients" may be individuals or organizations.
  138.86 -
  138.87 -  To "modify" a work means to copy from or adapt all or part of the work
  138.88 -in a fashion requiring copyright permission, other than the making of an
  138.89 -exact copy.  The resulting work is called a "modified version" of the
  138.90 -earlier work or a work "based on" the earlier work.
  138.91 -
  138.92 -  A "covered work" means either the unmodified Program or a work based
  138.93 -on the Program.
  138.94 -
  138.95 -  To "propagate" a work means to do anything with it that, without
  138.96 -permission, would make you directly or secondarily liable for
  138.97 -infringement under applicable copyright law, except executing it on a
  138.98 -computer or modifying a private copy.  Propagation includes copying,
  138.99 -distribution (with or without modification), making available to the
 138.100 -public, and in some countries other activities as well.
 138.101 -
 138.102 -  To "convey" a work means any kind of propagation that enables other
 138.103 -parties to make or receive copies.  Mere interaction with a user through
 138.104 -a computer network, with no transfer of a copy, is not conveying.
 138.105 -
 138.106 -  An interactive user interface displays "Appropriate Legal Notices"
 138.107 -to the extent that it includes a convenient and prominently visible
 138.108 -feature that (1) displays an appropriate copyright notice, and (2)
 138.109 -tells the user that there is no warranty for the work (except to the
 138.110 -extent that warranties are provided), that licensees may convey the
 138.111 -work under this License, and how to view a copy of this License.  If
 138.112 -the interface presents a list of user commands or options, such as a
 138.113 -menu, a prominent item in the list meets this criterion.
 138.114 -
 138.115 -  1. Source Code.
 138.116 -
 138.117 -  The "source code" for a work means the preferred form of the work
 138.118 -for making modifications to it.  "Object code" means any non-source
 138.119 -form of a work.
 138.120 -
 138.121 -  A "Standard Interface" means an interface that either is an official
 138.122 -standard defined by a recognized standards body, or, in the case of
 138.123 -interfaces specified for a particular programming language, one that
 138.124 -is widely used among developers working in that language.
 138.125 -
 138.126 -  The "System Libraries" of an executable work include anything, other
 138.127 -than the work as a whole, that (a) is included in the normal form of
 138.128 -packaging a Major Component, but which is not part of that Major
 138.129 -Component, and (b) serves only to enable use of the work with that
 138.130 -Major Component, or to implement a Standard Interface for which an
 138.131 -implementation is available to the public in source code form.  A
 138.132 -"Major Component", in this context, means a major essential component
 138.133 -(kernel, window system, and so on) of the specific operating system
 138.134 -(if any) on which the executable work runs, or a compiler used to
 138.135 -produce the work, or an object code interpreter used to run it.
 138.136 -
 138.137 -  The "Corresponding Source" for a work in object code form means all
 138.138 -the source code needed to generate, install, and (for an executable
 138.139 -work) run the object code and to modify the work, including scripts to
 138.140 -control those activities.  However, it does not include the work's
 138.141 -System Libraries, or general-purpose tools or generally available free
 138.142 -programs which are used unmodified in performing those activities but
 138.143 -which are not part of the work.  For example, Corresponding Source
 138.144 -includes interface definition files associated with source files for
 138.145 -the work, and the source code for shared libraries and dynamically
 138.146 -linked subprograms that the work is specifically designed to require,
 138.147 -such as by intimate data communication or control flow between those
 138.148 -subprograms and other parts of the work.
 138.149 -
 138.150 -  The Corresponding Source need not include anything that users
 138.151 -can regenerate automatically from other parts of the Corresponding
 138.152 -Source.
 138.153 -
 138.154 -  The Corresponding Source for a work in source code form is that
 138.155 -same work.
 138.156 -
 138.157 -  2. Basic Permissions.
 138.158 -
 138.159 -  All rights granted under this License are granted for the term of
 138.160 -copyright on the Program, and are irrevocable provided the stated
 138.161 -conditions are met.  This License explicitly affirms your unlimited
 138.162 -permission to run the unmodified Program.  The output from running a
 138.163 -covered work is covered by this License only if the output, given its
 138.164 -content, constitutes a covered work.  This License acknowledges your
 138.165 -rights of fair use or other equivalent, as provided by copyright law.
 138.166 -
 138.167 -  You may make, run and propagate covered works that you do not
 138.168 -convey, without conditions so long as your license otherwise remains
 138.169 -in force.  You may convey covered works to others for the sole purpose
 138.170 -of having them make modifications exclusively for you, or provide you
 138.171 -with facilities for running those works, provided that you comply with
 138.172 -the terms of this License in conveying all material for which you do
 138.173 -not control copyright.  Those thus making or running the covered works
 138.174 -for you must do so exclusively on your behalf, under your direction
 138.175 -and control, on terms that prohibit them from making any copies of
 138.176 -your copyrighted material outside their relationship with you.
 138.177 -
 138.178 -  Conveying under any other circumstances is permitted solely under
 138.179 -the conditions stated below.  Sublicensing is not allowed; section 10
 138.180 -makes it unnecessary.
 138.181 -
 138.182 -  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 138.183 -
 138.184 -  No covered work shall be deemed part of an effective technological
 138.185 -measure under any applicable law fulfilling obligations under article
 138.186 -11 of the WIPO copyright treaty adopted on 20 December 1996, or
 138.187 -similar laws prohibiting or restricting circumvention of such
 138.188 -measures.
 138.189 -
 138.190 -  When you convey a covered work, you waive any legal power to forbid
 138.191 -circumvention of technological measures to the extent such circumvention
 138.192 -is effected by exercising rights under this License with respect to
 138.193 -the covered work, and you disclaim any intention to limit operation or
 138.194 -modification of the work as a means of enforcing, against the work's
 138.195 -users, your or third parties' legal rights to forbid circumvention of
 138.196 -technological measures.
 138.197 -
 138.198 -  4. Conveying Verbatim Copies.
 138.199 -
 138.200 -  You may convey verbatim copies of the Program's source code as you
 138.201 -receive it, in any medium, provided that you conspicuously and
 138.202 -appropriately publish on each copy an appropriate copyright notice;
 138.203 -keep intact all notices stating that this License and any
 138.204 -non-permissive terms added in accord with section 7 apply to the code;
 138.205 -keep intact all notices of the absence of any warranty; and give all
 138.206 -recipients a copy of this License along with the Program.
 138.207 -
 138.208 -  You may charge any price or no price for each copy that you convey,
 138.209 -and you may offer support or warranty protection for a fee.
 138.210 -
 138.211 -  5. Conveying Modified Source Versions.
 138.212 -
 138.213 -  You may convey a work based on the Program, or the modifications to
 138.214 -produce it from the Program, in the form of source code under the
 138.215 -terms of section 4, provided that you also meet all of these conditions:
 138.216 -
 138.217 -    a) The work must carry prominent notices stating that you modified
 138.218 -    it, and giving a relevant date.
 138.219 -
 138.220 -    b) The work must carry prominent notices stating that it is
 138.221 -    released under this License and any conditions added under section
 138.222 -    7.  This requirement modifies the requirement in section 4 to
 138.223 -    "keep intact all notices".
 138.224 -
 138.225 -    c) You must license the entire work, as a whole, under this
 138.226 -    License to anyone who comes into possession of a copy.  This
 138.227 -    License will therefore apply, along with any applicable section 7
 138.228 -    additional terms, to the whole of the work, and all its parts,
 138.229 -    regardless of how they are packaged.  This License gives no
 138.230 -    permission to license the work in any other way, but it does not
 138.231 -    invalidate such permission if you have separately received it.
 138.232 -
 138.233 -    d) If the work has interactive user interfaces, each must display
 138.234 -    Appropriate Legal Notices; however, if the Program has interactive
 138.235 -    interfaces that do not display Appropriate Legal Notices, your
 138.236 -    work need not make them do so.
 138.237 -
 138.238 -  A compilation of a covered work with other separate and independent
 138.239 -works, which are not by their nature extensions of the covered work,
 138.240 -and which are not combined with it such as to form a larger program,
 138.241 -in or on a volume of a storage or distribution medium, is called an
 138.242 -"aggregate" if the compilation and its resulting copyright are not
 138.243 -used to limit the access or legal rights of the compilation's users
 138.244 -beyond what the individual works permit.  Inclusion of a covered work
 138.245 -in an aggregate does not cause this License to apply to the other
 138.246 -parts of the aggregate.
 138.247 -
 138.248 -  6. Conveying Non-Source Forms.
 138.249 -
 138.250 -  You may convey a covered work in object code form under the terms
 138.251 -of sections 4 and 5, provided that you also convey the
 138.252 -machine-readable Corresponding Source under the terms of this License,
 138.253 -in one of these ways:
 138.254 -
 138.255 -    a) Convey the object code in, or embodied in, a physical product
 138.256 -    (including a physical distribution medium), accompanied by the
 138.257 -    Corresponding Source fixed on a durable physical medium
 138.258 -    customarily used for software interchange.
 138.259 -
 138.260 -    b) Convey the object code in, or embodied in, a physical product
 138.261 -    (including a physical distribution medium), accompanied by a
 138.262 -    written offer, valid for at least three years and valid for as
 138.263 -    long as you offer spare parts or customer support for that product
 138.264 -    model, to give anyone who possesses the object code either (1) a
 138.265 -    copy of the Corresponding Source for all the software in the
 138.266 -    product that is covered by this License, on a durable physical
 138.267 -    medium customarily used for software interchange, for a price no
 138.268 -    more than your reasonable cost of physically performing this
 138.269 -    conveying of source, or (2) access to copy the
 138.270 -    Corresponding Source from a network server at no charge.
 138.271 -
 138.272 -    c) Convey individual copies of the object code with a copy of the
 138.273 -    written offer to provide the Corresponding Source.  This
 138.274 -    alternative is allowed only occasionally and noncommercially, and
 138.275 -    only if you received the object code with such an offer, in accord
 138.276 -    with subsection 6b.
 138.277 -
 138.278 -    d) Convey the object code by offering access from a designated
 138.279 -    place (gratis or for a charge), and offer equivalent access to the
 138.280 -    Corresponding Source in the same way through the same place at no
 138.281 -    further charge.  You need not require recipients to copy the
 138.282 -    Corresponding Source along with the object code.  If the place to
 138.283 -    copy the object code is a network server, the Corresponding Source
 138.284 -    may be on a different server (operated by you or a third party)
 138.285 -    that supports equivalent copying facilities, provided you maintain
 138.286 -    clear directions next to the object code saying where to find the
 138.287 -    Corresponding Source.  Regardless of what server hosts the
 138.288 -    Corresponding Source, you remain obligated to ensure that it is
 138.289 -    available for as long as needed to satisfy these requirements.
 138.290 -
 138.291 -    e) Convey the object code using peer-to-peer transmission, provided
 138.292 -    you inform other peers where the object code and Corresponding
 138.293 -    Source of the work are being offered to the general public at no
 138.294 -    charge under subsection 6d.
 138.295 -
 138.296 -  A separable portion of the object code, whose source code is excluded
 138.297 -from the Corresponding Source as a System Library, need not be
 138.298 -included in conveying the object code work.
 138.299 -
 138.300 -  A "User Product" is either (1) a "consumer product", which means any
 138.301 -tangible personal property which is normally used for personal, family,
 138.302 -or household purposes, or (2) anything designed or sold for incorporation
 138.303 -into a dwelling.  In determining whether a product is a consumer product,
 138.304 -doubtful cases shall be resolved in favor of coverage.  For a particular
 138.305 -product received by a particular user, "normally used" refers to a
 138.306 -typical or common use of that class of product, regardless of the status
 138.307 -of the particular user or of the way in which the particular user
 138.308 -actually uses, or expects or is expected to use, the product.  A product
 138.309 -is a consumer product regardless of whether the product has substantial
 138.310 -commercial, industrial or non-consumer uses, unless such uses represent
 138.311 -the only significant mode of use of the product.
 138.312 -
 138.313 -  "Installation Information" for a User Product means any methods,
 138.314 -procedures, authorization keys, or other information required to install
 138.315 -and execute modified versions of a covered work in that User Product from
 138.316 -a modified version of its Corresponding Source.  The information must
 138.317 -suffice to ensure that the continued functioning of the modified object
 138.318 -code is in no case prevented or interfered with solely because
 138.319 -modification has been made.
 138.320 -
 138.321 -  If you convey an object code work under this section in, or with, or
 138.322 -specifically for use in, a User Product, and the conveying occurs as
 138.323 -part of a transaction in which the right of possession and use of the
 138.324 -User Product is transferred to the recipient in perpetuity or for a
 138.325 -fixed term (regardless of how the transaction is characterized), the
 138.326 -Corresponding Source conveyed under this section must be accompanied
 138.327 -by the Installation Information.  But this requirement does not apply
 138.328 -if neither you nor any third party retains the ability to install
 138.329 -modified object code on the User Product (for example, the work has
 138.330 -been installed in ROM).
 138.331 -
 138.332 -  The requirement to provide Installation Information does not include a
 138.333 -requirement to continue to provide support service, warranty, or updates
 138.334 -for a work that has been modified or installed by the recipient, or for
 138.335 -the User Product in which it has been modified or installed.  Access to a
 138.336 -network may be denied when the modification itself materially and
 138.337 -adversely affects the operation of the network or violates the rules and
 138.338 -protocols for communication across the network.
 138.339 -
 138.340 -  Corresponding Source conveyed, and Installation Information provided,
 138.341 -in accord with this section must be in a format that is publicly
 138.342 -documented (and with an implementation available to the public in
 138.343 -source code form), and must require no special password or key for
 138.344 -unpacking, reading or copying.
 138.345 -
 138.346 -  7. Additional Terms.
 138.347 -
 138.348 -  "Additional permissions" are terms that supplement the terms of this
 138.349 -License by making exceptions from one or more of its conditions.
 138.350 -Additional permissions that are applicable to the entire Program shall
 138.351 -be treated as though they were included in this License, to the extent
 138.352 -that they are valid under applicable law.  If additional permissions
 138.353 -apply only to part of the Program, that part may be used separately
 138.354 -under those permissions, but the entire Program remains governed by
 138.355 -this License without regard to the additional permissions.
 138.356 -
 138.357 -  When you convey a copy of a covered work, you may at your option
 138.358 -remove any additional permissions from that copy, or from any part of
 138.359 -it.  (Additional permissions may be written to require their own
 138.360 -removal in certain cases when you modify the work.)  You may place
 138.361 -additional permissions on material, added by you to a covered work,
 138.362 -for which you have or can give appropriate copyright permission.
 138.363 -
 138.364 -  Notwithstanding any other provision of this License, for material you
 138.365 -add to a covered work, you may (if authorized by the copyright holders of
 138.366 -that material) supplement the terms of this License with terms:
 138.367 -
 138.368 -    a) Disclaiming warranty or limiting liability differently from the
 138.369 -    terms of sections 15 and 16 of this License; or
 138.370 -
 138.371 -    b) Requiring preservation of specified reasonable legal notices or
 138.372 -    author attributions in that material or in the Appropriate Legal
 138.373 -    Notices displayed by works containing it; or
 138.374 -
 138.375 -    c) Prohibiting misrepresentation of the origin of that material, or
 138.376 -    requiring that modified versions of such material be marked in
 138.377 -    reasonable ways as different from the original version; or
 138.378 -
 138.379 -    d) Limiting the use for publicity purposes of names of licensors or
 138.380 -    authors of the material; or
 138.381 -
 138.382 -    e) Declining to grant rights under trademark law for use of some
 138.383 -    trade names, trademarks, or service marks; or
 138.384 -
 138.385 -    f) Requiring indemnification of licensors and authors of that
 138.386 -    material by anyone who conveys the material (or modified versions of
 138.387 -    it) with contractual assumptions of liability to the recipient, for
 138.388 -    any liability that these contractual assumptions directly impose on
 138.389 -    those licensors and authors.
 138.390 -
 138.391 -  All other non-permissive additional terms are considered "further
 138.392 -restrictions" within the meaning of section 10.  If the Program as you
 138.393 -received it, or any part of it, contains a notice stating that it is
 138.394 -governed by this License along with a term that is a further
 138.395 -restriction, you may remove that term.  If a license document contains
 138.396 -a further restriction but permits relicensing or conveying under this
 138.397 -License, you may add to a covered work material governed by the terms
 138.398 -of that license document, provided that the further restriction does
 138.399 -not survive such relicensing or conveying.
 138.400 -
 138.401 -  If you add terms to a covered work in accord with this section, you
 138.402 -must place, in the relevant source files, a statement of the
 138.403 -additional terms that apply to those files, or a notice indicating
 138.404 -where to find the applicable terms.
 138.405 -
 138.406 -  Additional terms, permissive or non-permissive, may be stated in the
 138.407 -form of a separately written license, or stated as exceptions;
 138.408 -the above requirements apply either way.
 138.409 -
 138.410 -  8. Termination.
 138.411 -
 138.412 -  You may not propagate or modify a covered work except as expressly
 138.413 -provided under this License.  Any attempt otherwise to propagate or
 138.414 -modify it is void, and will automatically terminate your rights under
 138.415 -this License (including any patent licenses granted under the third
 138.416 -paragraph of section 11).
 138.417 -
 138.418 -  However, if you cease all violation of this License, then your
 138.419 -license from a particular copyright holder is reinstated (a)
 138.420 -provisionally, unless and until the copyright holder explicitly and
 138.421 -finally terminates your license, and (b) permanently, if the copyright
 138.422 -holder fails to notify you of the violation by some reasonable means
 138.423 -prior to 60 days after the cessation.
 138.424 -
 138.425 -  Moreover, your license from a particular copyright holder is
 138.426 -reinstated permanently if the copyright holder notifies you of the
 138.427 -violation by some reasonable means, this is the first time you have
 138.428 -received notice of violation of this License (for any work) from that
 138.429 -copyright holder, and you cure the violation prior to 30 days after
 138.430 -your receipt of the notice.
 138.431 -
 138.432 -  Termination of your rights under this section does not terminate the
 138.433 -licenses of parties who have received copies or rights from you under
 138.434 -this License.  If your rights have been terminated and not permanently
 138.435 -reinstated, you do not qualify to receive new licenses for the same
 138.436 -material under section 10.
 138.437 -
 138.438 -  9. Acceptance Not Required for Having Copies.
 138.439 -
 138.440 -  You are not required to accept this License in order to receive or
 138.441 -run a copy of the Program.  Ancillary propagation of a covered work
 138.442 -occurring solely as a consequence of using peer-to-peer transmission
 138.443 -to receive a copy likewise does not require acceptance.  However,
 138.444 -nothing other than this License grants you permission to propagate or
 138.445 -modify any covered work.  These actions infringe copyright if you do
 138.446 -not accept this License.  Therefore, by modifying or propagating a
 138.447 -covered work, you indicate your acceptance of this License to do so.
 138.448 -
 138.449 -  10. Automatic Licensing of Downstream Recipients.
 138.450 -
 138.451 -  Each time you convey a covered work, the recipient automatically
 138.452 -receives a license from the original licensors, to run, modify and
 138.453 -propagate that work, subject to this License.  You are not responsible
 138.454 -for enforcing compliance by third parties with this License.
 138.455 -
 138.456 -  An "entity transaction" is a transaction transferring control of an
 138.457 -organization, or substantially all assets of one, or subdividing an
 138.458 -organization, or merging organizations.  If propagation of a covered
 138.459 -work results from an entity transaction, each party to that
 138.460 -transaction who receives a copy of the work also receives whatever
 138.461 -licenses to the work the party's predecessor in interest had or could
 138.462 -give under the previous paragraph, plus a right to possession of the
 138.463 -Corresponding Source of the work from the predecessor in interest, if
 138.464 -the predecessor has it or can get it with reasonable efforts.
 138.465 -
 138.466 -  You may not impose any further restrictions on the exercise of the
 138.467 -rights granted or affirmed under this License.  For example, you may
 138.468 -not impose a license fee, royalty, or other charge for exercise of
 138.469 -rights granted under this License, and you may not initiate litigation
 138.470 -(including a cross-claim or counterclaim in a lawsuit) alleging that
 138.471 -any patent claim is infringed by making, using, selling, offering for
 138.472 -sale, or importing the Program or any portion of it.
 138.473 -
 138.474 -  11. Patents.
 138.475 -
 138.476 -  A "contributor" is a copyright holder who authorizes use under this
 138.477 -License of the Program or a work on which the Program is based.  The
 138.478 -work thus licensed is called the contributor's "contributor version".
 138.479 -
 138.480 -  A contributor's "essential patent claims" are all patent claims
 138.481 -owned or controlled by the contributor, whether already acquired or
 138.482 -hereafter acquired, that would be infringed by some manner, permitted
 138.483 -by this License, of making, using, or selling its contributor version,
 138.484 -but do not include claims that would be infringed only as a
 138.485 -consequence of further modification of the contributor version.  For
 138.486 -purposes of this definition, "control" includes the right to grant
 138.487 -patent sublicenses in a manner consistent with the requirements of
 138.488 -this License.
 138.489 -
 138.490 -  Each contributor grants you a non-exclusive, worldwide, royalty-free
 138.491 -patent license under the contributor's essential patent claims, to
 138.492 -make, use, sell, offer for sale, import and otherwise run, modify and
 138.493 -propagate the contents of its contributor version.
 138.494 -
 138.495 -  In the following three paragraphs, a "patent license" is any express
 138.496 -agreement or commitment, however denominated, not to enforce a patent
 138.497 -(such as an express permission to practice a patent or covenant not to
 138.498 -sue for patent infringement).  To "grant" such a patent license to a
 138.499 -party means to make such an agreement or commitment not to enforce a
 138.500 -patent against the party.
 138.501 -
 138.502 -  If you convey a covered work, knowingly relying on a patent license,
 138.503 -and the Corresponding Source of the work is not available for anyone
 138.504 -to copy, free of charge and under the terms of this License, through a
 138.505 -publicly available network server or other readily accessible means,
 138.506 -then you must either (1) cause the Corresponding Source to be so
 138.507 -available, or (2) arrange to deprive yourself of the benefit of the
 138.508 -patent license for this particular work, or (3) arrange, in a manner
 138.509 -consistent with the requirements of this License, to extend the patent
 138.510 -license to downstream recipients.  "Knowingly relying" means you have
 138.511 -actual knowledge that, but for the patent license, your conveying the
 138.512 -covered work in a country, or your recipient's use of the covered work
 138.513 -in a country, would infringe one or more identifiable patents in that
 138.514 -country that you have reason to believe are valid.
 138.515 -
 138.516 -  If, pursuant to or in connection with a single transaction or
 138.517 -arrangement, you convey, or propagate by procuring conveyance of, a
 138.518 -covered work, and grant a patent license to some of the parties
 138.519 -receiving the covered work authorizing them to use, propagate, modify
 138.520 -or convey a specific copy of the covered work, then the patent license
 138.521 -you grant is automatically extended to all recipients of the covered
 138.522 -work and works based on it.
 138.523 -
 138.524 -  A patent license is "discriminatory" if it does not include within
 138.525 -the scope of its coverage, prohibits the exercise of, or is
 138.526 -conditioned on the non-exercise of one or more of the rights that are
 138.527 -specifically granted under this License.  You may not convey a covered
 138.528 -work if you are a party to an arrangement with a third party that is
 138.529 -in the business of distributing software, under which you make payment
 138.530 -to the third party based on the extent of your activity of conveying
 138.531 -the work, and under which the third party grants, to any of the
 138.532 -parties who would receive the covered work from you, a discriminatory
 138.533 -patent license (a) in connection with copies of the covered work
 138.534 -conveyed by you (or copies made from those copies), or (b) primarily
 138.535 -for and in connection with specific products or compilations that
 138.536 -contain the covered work, unless you entered into that arrangement,
 138.537 -or that patent license was granted, prior to 28 March 2007.
 138.538 -
 138.539 -  Nothing in this License shall be construed as excluding or limiting
 138.540 -any implied license or other defenses to infringement that may
 138.541 -otherwise be available to you under applicable patent law.
 138.542 -
 138.543 -  12. No Surrender of Others' Freedom.
 138.544 -
 138.545 -  If conditions are imposed on you (whether by court order, agreement or
 138.546 -otherwise) that contradict the conditions of this License, they do not
 138.547 -excuse you from the conditions of this License.  If you cannot convey a
 138.548 -covered work so as to satisfy simultaneously your obligations under this
 138.549 -License and any other pertinent obligations, then as a consequence you may
 138.550 -not convey it at all.  For example, if you agree to terms that obligate you
 138.551 -to collect a royalty for further conveying from those to whom you convey
 138.552 -the Program, the only way you could satisfy both those terms and this
 138.553 -License would be to refrain entirely from conveying the Program.
 138.554 -
 138.555 -  13. Use with the GNU Affero General Public License.
 138.556 -
 138.557 -  Notwithstanding any other provision of this License, you have
 138.558 -permission to link or combine any covered work with a work licensed
 138.559 -under version 3 of the GNU Affero General Public License into a single
 138.560 -combined work, and to convey the resulting work.  The terms of this
 138.561 -License will continue to apply to the part which is the covered work,
 138.562 -but the special requirements of the GNU Affero General Public License,
 138.563 -section 13, concerning interaction through a network will apply to the
 138.564 -combination as such.
 138.565 -
 138.566 -  14. Revised Versions of this License.
 138.567 -
 138.568 -  The Free Software Foundation may publish revised and/or new versions of
 138.569 -the GNU General Public License from time to time.  Such new versions will
 138.570 -be similar in spirit to the present version, but may differ in detail to
 138.571 -address new problems or concerns.
 138.572 -
 138.573 -  Each version is given a distinguishing version number.  If the
 138.574 -Program specifies that a certain numbered version of the GNU General
 138.575 -Public License "or any later version" applies to it, you have the
 138.576 -option of following the terms and conditions either of that numbered
 138.577 -version or of any later version published by the Free Software
 138.578 -Foundation.  If the Program does not specify a version number of the
 138.579 -GNU General Public License, you may choose any version ever published
 138.580 -by the Free Software Foundation.
 138.581 -
 138.582 -  If the Program specifies that a proxy can decide which future
 138.583 -versions of the GNU General Public License can be used, that proxy's
 138.584 -public statement of acceptance of a version permanently authorizes you
 138.585 -to choose that version for the Program.
 138.586 -
 138.587 -  Later license versions may give you additional or different
 138.588 -permissions.  However, no additional obligations are imposed on any
 138.589 -author or copyright holder as a result of your choosing to follow a
 138.590 -later version.
 138.591 -
 138.592 -  15. Disclaimer of Warranty.
 138.593 -
 138.594 -  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
 138.595 -APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
 138.596 -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
 138.597 -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 138.598 -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 138.599 -PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
 138.600 -IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 138.601 -ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 138.602 -
 138.603 -  16. Limitation of Liability.
 138.604 -
 138.605 -  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 138.606 -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
 138.607 -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 138.608 -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
 138.609 -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
 138.610 -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
 138.611 -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
 138.612 -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
 138.613 -SUCH DAMAGES.
 138.614 -
 138.615 -  17. Interpretation of Sections 15 and 16.
 138.616 -
 138.617 -  If the disclaimer of warranty and limitation of liability provided
 138.618 -above cannot be given local legal effect according to their terms,
 138.619 -reviewing courts shall apply local law that most closely approximates
 138.620 -an absolute waiver of all civil liability in connection with the
 138.621 -Program, unless a warranty or assumption of liability accompanies a
 138.622 -copy of the Program in return for a fee.
 138.623 -
 138.624 -                     END OF TERMS AND CONDITIONS
 138.625 -
 138.626 -            How to Apply These Terms to Your New Programs
 138.627 -
 138.628 -  If you develop a new program, and you want it to be of the greatest
 138.629 -possible use to the public, the best way to achieve this is to make it
 138.630 -free software which everyone can redistribute and change under these terms.
 138.631 -
 138.632 -  To do so, attach the following notices to the program.  It is safest
 138.633 -to attach them to the start of each source file to most effectively
 138.634 -state the exclusion of warranty; and each file should have at least
 138.635 -the "copyright" line and a pointer to where the full notice is found.
 138.636 -
 138.637 -    <one line to give the program's name and a brief idea of what it does.>
 138.638 -    Copyright (C) <year>  <name of author>
 138.639 -
 138.640 -    This program is free software: you can redistribute it and/or modify
 138.641 -    it under the terms of the GNU General Public License as published by
 138.642 -    the Free Software Foundation, either version 3 of the License, or
 138.643 -    (at your option) any later version.
 138.644 -
 138.645 -    This program is distributed in the hope that it will be useful,
 138.646 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
 138.647 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 138.648 -    GNU General Public License for more details.
 138.649 -
 138.650 -    You should have received a copy of the GNU General Public License
 138.651 -    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 138.652 -
 138.653 -Also add information on how to contact you by electronic and paper mail.
 138.654 -
 138.655 -  If the program does terminal interaction, make it output a short
 138.656 -notice like this when it starts in an interactive mode:
 138.657 -
 138.658 -    <program>  Copyright (C) <year>  <name of author>
 138.659 -    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 138.660 -    This is free software, and you are welcome to redistribute it
 138.661 -    under certain conditions; type `show c' for details.
 138.662 -
 138.663 -The hypothetical commands `show w' and `show c' should show the appropriate
 138.664 -parts of the General Public License.  Of course, your program's commands
 138.665 -might be different; for a GUI interface, you would use an "about box".
 138.666 -
 138.667 -  You should also get your employer (if you work as a programmer) or school,
 138.668 -if any, to sign a "copyright disclaimer" for the program, if necessary.
 138.669 -For more information on this, and how to apply and follow the GNU GPL, see
 138.670 -<http://www.gnu.org/licenses/>.
 138.671 -
 138.672 -  The GNU General Public License does not permit incorporating your program
 138.673 -into proprietary programs.  If your program is a subroutine library, you
 138.674 -may consider it more useful to permit linking proprietary applications with
 138.675 -the library.  If this is what you want to do, use the GNU Lesser General
 138.676 -Public License instead of this License.  But first, please read
 138.677 -<http://www.gnu.org/philosophy/why-not-lgpl.html>.
 138.678 \ No newline at end of file
   139.1 --- a/trunk/README	Tue Jan 20 10:21:03 2009 +0100
   139.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   139.3 @@ -1,24 +0,0 @@
   139.4 -n3tpd README
   139.5 -============
   139.6 -
   139.7 -Prerequisites:
   139.8 ---------------
   139.9 -
  139.10 -* Java Runtime, Version 1.5
  139.11 -* MySQL, Version 5 or higher
  139.12 -* Java-MySQL-Connector (JDBC driver)
  139.13 -
  139.14 -
  139.15 -Installation:
  139.16 --------------
  139.17 -
  139.18 -* Create a database in your DBMS, e.g. named like 'n3tpd_data'
  139.19 -* Create the necessary table structure using the helpers/table.sql file
  139.20 -* Customize the settings within the n3tpd.conf file
  139.21 -* Invoke 'java -jar n3tpd.jar' to start the daemon
  139.22 -
  139.23 -Bugs and other Issues:
  139.24 -----------------------
  139.25 -
  139.26 -Please mail them to christian.lins@web.de or, better, issue them
  139.27 -into our bugtracker at http://bugs.netvader.net/ .
  139.28 \ No newline at end of file
   140.1 --- a/trunk/TODO	Tue Jan 20 10:21:03 2009 +0100
   140.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   140.3 @@ -1,10 +0,0 @@
   140.4 -TODO
   140.5 -====
   140.6 -
   140.7 -* Implement new SQL table structure
   140.8 -* Implement a --init-tables command that creates the necessary database/tables
   140.9 -
  140.10 -ROADMAP
  140.11 -=======
  140.12 -
  140.13 -Version 1.0 must be fully RFC3977 compliant.
  140.14 \ No newline at end of file
   141.1 --- a/trunk/com/so/news/Config.java	Tue Jan 20 10:21:03 2009 +0100
   141.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   141.3 @@ -1,198 +0,0 @@
   141.4 -/*
   141.5 - *   StarOffice News Server
   141.6 - *   see AUTHORS for the list of contributors
   141.7 - *
   141.8 - *   This program is free software: you can redistribute it and/or modify
   141.9 - *   it under the terms of the GNU General Public License as published by
  141.10 - *   the Free Software Foundation, either version 3 of the License, or
  141.11 - *   (at your option) any later version.
  141.12 - *
  141.13 - *   This program is distributed in the hope that it will be useful,
  141.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  141.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  141.16 - *   GNU General Public License for more details.
  141.17 - *
  141.18 - *   You should have received a copy of the GNU General Public License
  141.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  141.20 - */
  141.21 -
  141.22 -package com.so.news;
  141.23 -
  141.24 -import java.io.FileInputStream;
  141.25 -import java.io.FileNotFoundException;
  141.26 -import java.io.FileOutputStream;
  141.27 -import java.io.IOException;
  141.28 -import java.util.Properties;
  141.29 -
  141.30 -/**
  141.31 - * Manages the n3tpd configuration.
  141.32 - * @author Christian Lins
  141.33 - */
  141.34 -public class Config
  141.35 -{
  141.36 -  /** The filename of the logfile */
  141.37 -  public static final String CONFIG_N3TPD_LOGFILE = "n3tpd.logfile";
  141.38 -  
  141.39 -  /** The filename of the config file that is loaded on startup */
  141.40 -  public static final String FILE                 = "n3tpd.conf";
  141.41 -
  141.42 -  private static final Properties defaultConfig = new Properties();
  141.43 -  
  141.44 -  private static Config instance = null;
  141.45 -  
  141.46 -  static
  141.47 -  {
  141.48 -    // Set some default values
  141.49 -    defaultConfig.setProperty("n3tpd.article.lifetime", "300"); // 300 days
  141.50 -    defaultConfig.setProperty("n3tpd.article.maxsize", "100");  // 100 kbyte
  141.51 -    defaultConfig.setProperty("n3tpd.port", "119");
  141.52 -    defaultConfig.setProperty("n3tpd.auxport", "8080");
  141.53 -    defaultConfig.setProperty("n3tpd.server.backlog", "10");
  141.54 -    defaultConfig.setProperty("n3tpd.hostname", "localhost");
  141.55 -    defaultConfig.setProperty("n3tpd.storage.database", "jdbc:mysql://localhost/n3tpd_data");
  141.56 -    defaultConfig.setProperty("n3tpd.storage.dbmsdriver", "com.mysql.jdbc.Driver");
  141.57 -    defaultConfig.setProperty("n3tpd.storage.user", "n3tpd_user");
  141.58 -    defaultConfig.setProperty("n3tpd.storage.password", "mysecret");
  141.59 -    
  141.60 -    instance = new Config();
  141.61 -  }
  141.62 -  
  141.63 -  /**
  141.64 -   * @return A Config instance
  141.65 -   */
  141.66 -  public static Config getInstance()
  141.67 -  {
  141.68 -    return instance;
  141.69 -  }
  141.70 -
  141.71 -  // Every config instance is initialized with the default values.
  141.72 -  private Properties settings = (Properties)defaultConfig.clone();
  141.73 -
  141.74 -  /**
  141.75 -   * Config is a singelton class with only one instance at time.
  141.76 -   * So the constructor is private to prevent the creation of more
  141.77 -   * then one Config instance.
  141.78 -   * @see Config.getInstance() to retrieve an instance of Config
  141.79 -   */
  141.80 -  private Config()
  141.81 -  {
  141.82 -    try
  141.83 -    {
  141.84 -      // Load settings from file
  141.85 -      load();
  141.86 -    }
  141.87 -    catch(IOException e)
  141.88 -    {
  141.89 -      e.printStackTrace();
  141.90 -    }
  141.91 -  }
  141.92 -
  141.93 -  /**
  141.94 -   * Loads the configuration from the config file. By default this is done
  141.95 -   * by the (private) constructor but it can be useful to reload the config
  141.96 -   * by invoking this method.
  141.97 -   * @throws IOException
  141.98 -   */
  141.99 -  public void load() throws IOException
 141.100 -  {
 141.101 -    try
 141.102 -    {
 141.103 -      settings.load(new FileInputStream(FILE));
 141.104 -    }
 141.105 -    catch (FileNotFoundException e)
 141.106 -    {
 141.107 -      save();
 141.108 -    }
 141.109 -  }
 141.110 -
 141.111 -  /**
 141.112 -   * Saves this Config to the config file. By default this is done
 141.113 -   * at program end.
 141.114 -   * @throws FileNotFoundException
 141.115 -   * @throws IOException
 141.116 -   */
 141.117 -  public void save() throws FileNotFoundException, IOException
 141.118 -  {
 141.119 -    settings.store(new FileOutputStream(FILE), "N3TPD Config File");
 141.120 -  }
 141.121 -  
 141.122 -  /**
 141.123 -   * Returns the value that is stored within this config
 141.124 -   * identified by the given key. If the key cannot be found
 141.125 -   * the default value is returned.
 141.126 -   * @param key Key to identify the value.
 141.127 -   * @param def The default value that is returned if the key
 141.128 -   * is not found in this Config.
 141.129 -   * @return
 141.130 -   */
 141.131 -  public String get(String key, String def)
 141.132 -  {
 141.133 -    return settings.getProperty(key, def);
 141.134 -  }
 141.135 -
 141.136 -  /**
 141.137 -   * Returns the value that is stored within this config
 141.138 -   * identified by the given key. If the key cannot be found
 141.139 -   * the default value is returned.
 141.140 -   * @param key Key to identify the value.
 141.141 -   * @param def The default value that is returned if the key
 141.142 -   * is not found in this Config.
 141.143 -   * @return
 141.144 -   */
 141.145 -  public int get(String key, int def)
 141.146 -  {
 141.147 -    try
 141.148 -    {
 141.149 -      String val = get(key);
 141.150 -      return Integer.parseInt(val);
 141.151 -    }
 141.152 -    catch(Exception e)
 141.153 -    {
 141.154 -      return def;
 141.155 -    }
 141.156 -  }
 141.157 -  
 141.158 -  /**
 141.159 -   * Returns the value that is stored within this config
 141.160 -   * identified by the given key. If the key cannot be found
 141.161 -   * the default value is returned.
 141.162 -   * @param key Key to identify the value.
 141.163 -   * @param def The default value that is returned if the key
 141.164 -   * is not found in this Config.
 141.165 -   * @return
 141.166 -   */
 141.167 -  public long get(String key, long def)
 141.168 -  {
 141.169 -    try
 141.170 -    {
 141.171 -      String val = get(key);
 141.172 -      return Long.parseLong(val);
 141.173 -    }
 141.174 -    catch(Exception e)
 141.175 -    {
 141.176 -      return def;
 141.177 -    }
 141.178 -  }
 141.179 -
 141.180 -  /**
 141.181 -   * Returns the value for the given key or null if the
 141.182 -   * key is not found in this Config.
 141.183 -   * @param key
 141.184 -   * @return
 141.185 -   */
 141.186 -  private String get(String key)
 141.187 -  {
 141.188 -    return settings.getProperty(key);
 141.189 -  }
 141.190 -
 141.191 -  /**
 141.192 -   * Sets the value for a given key.
 141.193 -   * @param key
 141.194 -   * @param value
 141.195 -   */
 141.196 -  public void set(String key, String value)
 141.197 -  {
 141.198 -    settings.setProperty(key, value);
 141.199 -  }
 141.200 -
 141.201 -}
   142.1 --- a/trunk/com/so/news/Debug.java	Tue Jan 20 10:21:03 2009 +0100
   142.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   142.3 @@ -1,95 +0,0 @@
   142.4 -/*
   142.5 - *   StarOffice News Server
   142.6 - *   see AUTHORS for the list of contributors
   142.7 - *
   142.8 - *   This program is free software: you can redistribute it and/or modify
   142.9 - *   it under the terms of the GNU General Public License as published by
  142.10 - *   the Free Software Foundation, either version 3 of the License, or
  142.11 - *   (at your option) any later version.
  142.12 - *
  142.13 - *   This program is distributed in the hope that it will be useful,
  142.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  142.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  142.16 - *   GNU General Public License for more details.
  142.17 - *
  142.18 - *   You should have received a copy of the GNU General Public License
  142.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  142.20 - */
  142.21 -
  142.22 -package com.so.news;
  142.23 -
  142.24 -import java.io.FileOutputStream;
  142.25 -import java.io.IOException;
  142.26 -import java.io.PrintStream;
  142.27 -import java.util.Date;
  142.28 -
  142.29 -/**
  142.30 - * Provides logging and debugging methods.
  142.31 - * @author Christian Lins
  142.32 - */
  142.33 -public class Debug
  142.34 -{
  142.35 -  private static Debug instance = null;
  142.36 -  
  142.37 -  /**
  142.38 -   * Returns the singelton instance of this class.
  142.39 -   */
  142.40 -  public static Debug getInstance()
  142.41 -  {
  142.42 -    if(instance == null)
  142.43 -      instance = new Debug();
  142.44 -    
  142.45 -    return instance;
  142.46 -  }
  142.47 -  
  142.48 -  private PrintStream out = System.err;
  142.49 -  
  142.50 -  /**
  142.51 -   * This class is a singelton class. The constructor is private to prevent
  142.52 -   * the creation of more than one instance.
  142.53 -   */
  142.54 -  private Debug()
  142.55 -  {
  142.56 -    try
  142.57 -    {
  142.58 -      String filename = Config.getInstance().get(Config.CONFIG_N3TPD_LOGFILE, "n3tpd.log");
  142.59 -      
  142.60 -      this.out = new PrintStream(new FileOutputStream(filename));
  142.61 -    }
  142.62 -    catch(IOException e)
  142.63 -    {
  142.64 -      e.printStackTrace();
  142.65 -    }
  142.66 -  }
  142.67 -  
  142.68 -  /**
  142.69 -   * Returns the debug output PrintStream. By default this is System.err.
  142.70 -   */
  142.71 -  public PrintStream getStream()
  142.72 -  {
  142.73 -    return out;
  142.74 -  }
  142.75 -  
  142.76 -  /**
  142.77 -   * Writes the given message to the debug output.
  142.78 -   * @param msg A String message or an object.
  142.79 -   */
  142.80 -  public void log(Object msg)
  142.81 -  {
  142.82 -    log(out, msg);
  142.83 -    log(System.out, msg);
  142.84 -  }
  142.85 -  
  142.86 -  /**
  142.87 -   * Writes the given debug message to the given PrintStream.
  142.88 -   * @param out
  142.89 -   * @param msg
  142.90 -   */
  142.91 -  public void log(PrintStream out, Object msg)
  142.92 -  {
  142.93 -    out.print(new Date().toString());
  142.94 -    out.print(": ");
  142.95 -    out.println(msg.toString());
  142.96 -    out.flush();
  142.97 -  }
  142.98 -}
   143.1 --- a/trunk/com/so/news/Main.java	Tue Jan 20 10:21:03 2009 +0100
   143.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.3 @@ -1,96 +0,0 @@
   143.4 -/*
   143.5 - *   StarOffice News Server
   143.6 - *   see AUTHORS for the list of contributors
   143.7 - *
   143.8 - *   This program is free software: you can redistribute it and/or modify
   143.9 - *   it under the terms of the GNU General Public License as published by
  143.10 - *   the Free Software Foundation, either version 3 of the License, or
  143.11 - *   (at your option) any later version.
  143.12 - *
  143.13 - *   This program is distributed in the hope that it will be useful,
  143.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  143.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  143.16 - *   GNU General Public License for more details.
  143.17 - *
  143.18 - *   You should have received a copy of the GNU General Public License
  143.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  143.20 - */
  143.21 -
  143.22 -package com.so.news;
  143.23 -
  143.24 -import java.net.BindException;
  143.25 -
  143.26 -import java.sql.Driver;
  143.27 -import java.sql.DriverManager;
  143.28 -import java.util.Enumeration;
  143.29 -
  143.30 -import com.so.news.storage.Database;
  143.31 -import com.so.news.storage.Purger;
  143.32 -
  143.33 -/**
  143.34 - * Startup class of the daemon.
  143.35 - * @author Christian Lins
  143.36 - */
  143.37 -public class Main
  143.38 -{
  143.39 -  /** Version information of the StarOffice News daemon */
  143.40 -  public static final String VERSION = "StarOffice News Server 0.5alpha1";
  143.41 -
  143.42 -  /**
  143.43 -   * The main entrypoint.
  143.44 -   * @param args
  143.45 -   * @throws Exception
  143.46 -   */
  143.47 -  public static void main(String args[]) throws Exception
  143.48 -  {
  143.49 -    System.out.println(VERSION);
  143.50 -
  143.51 -    // Command line arguments
  143.52 -    boolean auxPort = false;
  143.53 -    
  143.54 -    for(int n = 0; n < args.length; n++)
  143.55 -    {
  143.56 -      if(args[n].equals("--dumpjdbcdriver"))
  143.57 -      {
  143.58 -        System.out.println("Available JDBC drivers:");
  143.59 -        Enumeration<Driver> drvs =  DriverManager.getDrivers();
  143.60 -        while(drvs.hasMoreElements())
  143.61 -          System.out.println(drvs.nextElement());
  143.62 -        return;
  143.63 -      }
  143.64 -      else if(args[n].equals("--useaux"))
  143.65 -        auxPort = true;
  143.66 -    }
  143.67 -    
  143.68 -    // Try to load the Database
  143.69 -    try
  143.70 -    {
  143.71 -      Database.arise();
  143.72 -    }
  143.73 -    catch(Exception ex)
  143.74 -    {
  143.75 -      ex.printStackTrace(Debug.getInstance().getStream());
  143.76 -      System.err.println("Database initialization failed with " + ex.toString());
  143.77 -      
  143.78 -      return;
  143.79 -    }
  143.80 -    
  143.81 -    // Start the n3tpd garbage collector
  143.82 -    new Purger().start();
  143.83 -    
  143.84 -    // Start the listening daemon
  143.85 -    try
  143.86 -    {
  143.87 -      new NNTPDaemon(false).start();
  143.88 -    }
  143.89 -    catch(BindException ex)
  143.90 -    {
  143.91 -      ex.printStackTrace(Debug.getInstance().getStream());
  143.92 -      System.err.println("Could not bind to interface. Perhaps you need superuser rights?");
  143.93 -    }
  143.94 -    
  143.95 -    // Start auxilary listening port...
  143.96 -    if(auxPort)
  143.97 -      new NNTPDaemon(true).start();
  143.98 -  }
  143.99 -}
   144.1 --- a/trunk/com/so/news/NNTPConnection.java	Tue Jan 20 10:21:03 2009 +0100
   144.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   144.3 @@ -1,395 +0,0 @@
   144.4 -/*
   144.5 - *   StarOffice News Server
   144.6 - *   see AUTHORS for the list of contributors
   144.7 - *
   144.8 - *   This program is free software: you can redistribute it and/or modify
   144.9 - *   it under the terms of the GNU General Public License as published by
  144.10 - *   the Free Software Foundation, either version 3 of the License, or
  144.11 - *   (at your option) any later version.
  144.12 - *
  144.13 - *   This program is distributed in the hope that it will be useful,
  144.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  144.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  144.16 - *   GNU General Public License for more details.
  144.17 - *
  144.18 - *   You should have received a copy of the GNU General Public License
  144.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  144.20 - */
  144.21 -
  144.22 -package com.so.news;
  144.23 -
  144.24 -import java.io.BufferedReader;
  144.25 -import java.io.BufferedWriter;
  144.26 -import java.io.File;
  144.27 -import java.io.InputStreamReader;
  144.28 -import java.io.IOException;
  144.29 -import java.io.OutputStreamWriter;
  144.30 -import java.net.Socket;
  144.31 -import java.net.SocketException;
  144.32 -import java.text.SimpleDateFormat;
  144.33 -import java.util.Date;
  144.34 -import java.util.LinkedList;
  144.35 -import java.util.List;
  144.36 -import com.so.news.command.ArticleCommand;
  144.37 -import com.so.news.command.GroupCommand;
  144.38 -import com.so.news.command.ListCommand;
  144.39 -import com.so.news.command.PostCommand;
  144.40 -import com.so.news.command.OverCommand;
  144.41 -import com.so.news.storage.Article;
  144.42 -import com.so.news.storage.Group;
  144.43 -
  144.44 -/**
  144.45 - * Represents the connection between the server and one client.
  144.46 - * @author Christian Lins (christian.lins@web.de)
  144.47 - */
  144.48 -public class NNTPConnection extends Thread
  144.49 -{
  144.50 -  public static final String NEWLINE            = "\r\n";
  144.51 -  public static final String MESSAGE_ID_PATTERN = "<[^>]+>";
  144.52 -  
  144.53 -  private boolean            debug              
  144.54 -    = Boolean.parseBoolean(Config.getInstance().get("n3tpd.debug", "false"));
  144.55 -  private Socket             socket;
  144.56 -  private boolean            exit               = false;
  144.57 -  private BufferedWriter     out;
  144.58 -  private BufferedReader     in;
  144.59 -  private Article            currentArticle     = null;
  144.60 -  private Group              currentGroup       = null;
  144.61 -
  144.62 -  /**
  144.63 -   * Creates a new NNTPConnection instance using the given connected Socket.
  144.64 -   * @param socket
  144.65 -   * @throws java.io.IOException
  144.66 -   */
  144.67 -  public NNTPConnection(Socket socket) 
  144.68 -    throws IOException
  144.69 -  {
  144.70 -    this.socket = socket;
  144.71 -    this.in     = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  144.72 -    this.out    = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
  144.73 -    // TODO: The output stream should be of type PrintStream so that many
  144.74 -    // of the printX() methods of this class can go to trash
  144.75 -    
  144.76 -    setDaemon(true); // Exits if the main thread is killed
  144.77 -  }
  144.78 -
  144.79 -  /**
  144.80 -   * Closes the associated socket end exits the Thread.
  144.81 -   */
  144.82 -  public void exit()
  144.83 -  {
  144.84 -    try
  144.85 -    {
  144.86 -      exit = true;
  144.87 -      socket.close();
  144.88 -    }
  144.89 -    catch (Exception e)
  144.90 -    {
  144.91 -      e.printStackTrace();
  144.92 -    }
  144.93 -  }
  144.94 -
  144.95 -  /**
  144.96 -   * Prints a CharSequence to the sockets output stream.
  144.97 -   */
  144.98 -  public void print(CharSequence s) throws IOException
  144.99 -  {
 144.100 -    out.append(s);
 144.101 -  }
 144.102 -
 144.103 -  public void println(CharSequence s) throws IOException
 144.104 -  {
 144.105 -    print(s);
 144.106 -    print(NEWLINE);
 144.107 -    if (debug)
 144.108 -      System.out.println("<<< " + s);
 144.109 -  }
 144.110 -
 144.111 -  public void printStatus(int code, String description) throws IOException
 144.112 -  {
 144.113 -    println("" + code + " " + description);
 144.114 -    flush();
 144.115 -  }
 144.116 -
 144.117 -  public void printTextLine(CharSequence line) throws IOException
 144.118 -  {
 144.119 -    if (line.length() > 0 && line.charAt(0) == '.')
 144.120 -      print("..");
 144.121 -    println(line);
 144.122 -  }
 144.123 -
 144.124 -  public void printTextPart(CharSequence text) throws IOException
 144.125 -  {
 144.126 -    String[] lines = text.toString().split(NEWLINE);
 144.127 -    for (String line : lines)
 144.128 -      printTextLine(line);
 144.129 -  }
 144.130 -
 144.131 -  public void printText(CharSequence text) throws IOException
 144.132 -  {
 144.133 -    printTextPart(text);
 144.134 -    println(".");
 144.135 -    flush();
 144.136 -  }
 144.137 -
 144.138 -  public void flush() throws IOException
 144.139 -  {
 144.140 -    out.flush();
 144.141 -  }
 144.142 -
 144.143 -  public String readln() throws IOException
 144.144 -  {
 144.145 -    String s = in.readLine();
 144.146 -    if (s == null)
 144.147 -      throw new IOException("Socket closed");
 144.148 -    if (debug)
 144.149 -      System.out.println(">>> " + s);
 144.150 -    return s;
 144.151 -  }
 144.152 -
 144.153 -  public String[] readCommand() throws IOException
 144.154 -  {
 144.155 -    return readln().split("[ ]+");
 144.156 -  }
 144.157 -
 144.158 -  public List<String> readText() throws IOException
 144.159 -  {
 144.160 -    List<String> l = new LinkedList<String>();
 144.161 -    String s;
 144.162 -    do
 144.163 -    {
 144.164 -      s = readln();
 144.165 -      if (!s.equals("."))
 144.166 -      {
 144.167 -        if (s.startsWith(".."))
 144.168 -          s = s.substring(1);
 144.169 -        l.add(s);
 144.170 -      }
 144.171 -    }
 144.172 -    while (!s.equals("."));
 144.173 -    return l;
 144.174 -  }
 144.175 -
 144.176 -  public String readTextLine() throws IOException
 144.177 -  {
 144.178 -    String s = null;
 144.179 -    do
 144.180 -    {
 144.181 -      s = readln();
 144.182 -    }
 144.183 -    while (s == null);
 144.184 -    if (s.equals("."))
 144.185 -      return null;
 144.186 -    if (s.startsWith(".."))
 144.187 -      s = s.substring(1);
 144.188 -    return s;
 144.189 -  }
 144.190 -
 144.191 -  public void setCurrentArticle(Article current)
 144.192 -  {
 144.193 -    currentArticle = current;
 144.194 -  }
 144.195 -
 144.196 -  public Article getCurrentArticle()
 144.197 -  {
 144.198 -    return currentArticle;
 144.199 -  }
 144.200 -
 144.201 -  public void setCurrentGroup(Group current)
 144.202 -  {
 144.203 -    currentGroup = current;
 144.204 -  }
 144.205 -
 144.206 -  public Group getCurrentGroup()
 144.207 -  {
 144.208 -    return currentGroup;
 144.209 -  }
 144.210 -
 144.211 -  private void processCommand(String[] command) 
 144.212 -    throws Exception
 144.213 -  {
 144.214 -    if (command.length == 0)
 144.215 -      return; // TODO Error
 144.216 -
 144.217 -    String commandName = command[0];
 144.218 -
 144.219 -    // RFC977
 144.220 -    // TODO HELP command
 144.221 -    // TODO NEWGROUPS command
 144.222 -    // TODO NEWNEWS command
 144.223 -
 144.224 -    // RFC2980
 144.225 -    // TODO LIST ACTIVE command
 144.226 -    // TODO LIST ACTIVE.TIMES command
 144.227 -    // TODO LIST DISTRIBUTIONS command
 144.228 -    // TODO LIST DISTRIB.PATS command
 144.229 -    // TODO XGTITLE command
 144.230 -    // TODO XHDR command
 144.231 -    // TODO XPAT command
 144.232 -    // TODO XPATH command
 144.233 -    // TODO XROVER command
 144.234 -    // TODO XTHREAD command
 144.235 -    // TODO AUTHINFO command
 144.236 -
 144.237 -    // STANDARD COMMANDS
 144.238 -    if (commandName.equalsIgnoreCase("ARTICLE")
 144.239 -        || commandName.equalsIgnoreCase("STAT")
 144.240 -        || commandName.equalsIgnoreCase("HEAD") 
 144.241 -        || commandName.equalsIgnoreCase("BODY"))
 144.242 -    {
 144.243 -      ArticleCommand cmd = new ArticleCommand(this);
 144.244 -      cmd.process(command);
 144.245 -    }
 144.246 -    
 144.247 -    else if (commandName.equalsIgnoreCase("LIST"))
 144.248 -    {
 144.249 -      ListCommand cmd = new ListCommand(this);
 144.250 -      cmd.process(command);
 144.251 -    }
 144.252 -
 144.253 -    else if (commandName.equalsIgnoreCase("GROUP"))
 144.254 -    {
 144.255 -      GroupCommand cmd = new GroupCommand(this);
 144.256 -      cmd.process(command);
 144.257 -    }
 144.258 -    
 144.259 -    else if(commandName.equalsIgnoreCase("POST"))
 144.260 -    {
 144.261 -      PostCommand cmd = new PostCommand(this);
 144.262 -      cmd.process(command);
 144.263 -    }
 144.264 -
 144.265 -    else if (commandName.equalsIgnoreCase("CHECK")
 144.266 -        || commandName.equalsIgnoreCase("TAKETHIS"))
 144.267 -    {
 144.268 -      // untested, RFC2980 compliant
 144.269 -      printStatus(400, "not accepting articles");
 144.270 -      return;
 144.271 -    }
 144.272 -
 144.273 -    else if (commandName.equalsIgnoreCase("IHAVE")
 144.274 -        || commandName.equalsIgnoreCase("XREPLIC"))
 144.275 -    {
 144.276 -      // untested, RFC977 compliant
 144.277 -      printStatus(435, "article not wanted - do not send it");
 144.278 -      return;
 144.279 -    }
 144.280 -
 144.281 -    else if (commandName.equalsIgnoreCase("XCREATEGROUP"))
 144.282 -    {
 144.283 -      return;
 144.284 -    }
 144.285 -
 144.286 -    else if (commandName.equalsIgnoreCase("SLAVE"))
 144.287 -    {
 144.288 -      // untested, RFC977 compliant
 144.289 -      printStatus(202, "slave status noted");
 144.290 -      return;
 144.291 -    }
 144.292 -
 144.293 -    else if (commandName.equalsIgnoreCase("XINDEX"))
 144.294 -    {
 144.295 -      // untested, RFC2980 compliant
 144.296 -      printStatus(418, "no tin-style index is available for this news group");
 144.297 -      return;
 144.298 -    }
 144.299 -
 144.300 -    else if (commandName.equalsIgnoreCase("DATE"))
 144.301 -    {
 144.302 -      printStatus(111, new SimpleDateFormat("yyyyMMddHHmmss")
 144.303 -          .format(new Date()));
 144.304 -      return;
 144.305 -    }
 144.306 -
 144.307 -    else if (commandName.equalsIgnoreCase("MODE"))
 144.308 -    {
 144.309 -      if (command[1].equalsIgnoreCase("READER"))
 144.310 -      {
 144.311 -        // untested, RFC2980 compliant
 144.312 -        printStatus(200, "Hello, you can post");
 144.313 -      }
 144.314 -      else if (command[1].equalsIgnoreCase("STREAM"))
 144.315 -      {
 144.316 -        printStatus(203, "Streaming is OK");
 144.317 -      }
 144.318 -      else
 144.319 -        printStatus(501, "Command not supported");
 144.320 -    }
 144.321 -
 144.322 -    else if (commandName.equalsIgnoreCase("QUIT"))
 144.323 -    {
 144.324 -      // untested, RFC977 compliant
 144.325 -      printStatus(205, "closing connection - goodbye!");
 144.326 -      exit();
 144.327 -      return;
 144.328 -    }  
 144.329 -    
 144.330 -    else if (commandName.equalsIgnoreCase("XSHUTDOWN"))
 144.331 -    {
 144.332 -      printStatus(205, "closing connection - goodbye!");
 144.333 -      exit();
 144.334 -      return;
 144.335 -    }
 144.336 -
 144.337 -    // X COMMANDS
 144.338 -    else if(commandName.equalsIgnoreCase("XOVER")
 144.339 -       || commandName.equalsIgnoreCase("OVER"))
 144.340 -    {
 144.341 -      OverCommand cmd = new OverCommand(this);
 144.342 -      cmd.process(command);
 144.343 -    }
 144.344 -
 144.345 -    else
 144.346 -      printStatus(501, "Command not supported");
 144.347 -  }
 144.348 -
 144.349 -  /**
 144.350 -   * Runloop of this Thread.
 144.351 -   * @throws RuntimeException if this method is called directly.
 144.352 -   */
 144.353 -  @Override
 144.354 -  public void run()
 144.355 -  {
 144.356 -    assert !this.equals(Thread.currentThread());
 144.357 -
 144.358 -    try
 144.359 -    {
 144.360 -      printStatus(200, Config.getInstance().get("n3tpd.hostname", "localhost")
 144.361 -          + " " + Main.VERSION + " news server ready - (posting ok).");
 144.362 -    }
 144.363 -    catch (IOException e1)
 144.364 -    {
 144.365 -      exit();
 144.366 -    }
 144.367 -    
 144.368 -    while (!exit)
 144.369 -    {
 144.370 -      try
 144.371 -      {
 144.372 -        processCommand(readCommand());
 144.373 -      }
 144.374 -      catch (SocketException e)
 144.375 -      {
 144.376 -        if (exit)
 144.377 -          return;
 144.378 -        exit();
 144.379 -        e.printStackTrace();
 144.380 -      }
 144.381 -      catch (IOException e)
 144.382 -      {
 144.383 -        if (exit)
 144.384 -          return;
 144.385 -        exit();
 144.386 -        e.printStackTrace();
 144.387 -      }
 144.388 -      catch (Throwable e)
 144.389 -      {
 144.390 -        if (exit)
 144.391 -          return;
 144.392 -        e.printStackTrace();
 144.393 -        // silently ignore
 144.394 -      }
 144.395 -    }
 144.396 -  }
 144.397 -
 144.398 -}
   145.1 --- a/trunk/com/so/news/NNTPDaemon.java	Tue Jan 20 10:21:03 2009 +0100
   145.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   145.3 @@ -1,64 +0,0 @@
   145.4 -/*
   145.5 - *   StarOffice News Server
   145.6 - *   see AUTHORS for the list of contributors
   145.7 - *
   145.8 - *   This program is free software: you can redistribute it and/or modify
   145.9 - *   it under the terms of the GNU General Public License as published by
  145.10 - *   the Free Software Foundation, either version 3 of the License, or
  145.11 - *   (at your option) any later version.
  145.12 - *
  145.13 - *   This program is distributed in the hope that it will be useful,
  145.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  145.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  145.16 - *   GNU General Public License for more details.
  145.17 - *
  145.18 - *   You should have received a copy of the GNU General Public License
  145.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  145.20 - */
  145.21 -
  145.22 -package com.so.news;
  145.23 -
  145.24 -import java.io.IOException;
  145.25 -import java.net.ServerSocket;
  145.26 -
  145.27 -/**
  145.28 - * Server component of the n3tpd.
  145.29 - * @author Christian Lins
  145.30 - * @author Dennis Schwerdel
  145.31 - */
  145.32 -public class NNTPDaemon extends Thread
  145.33 -{
  145.34 -  private ServerSocket socket;
  145.35 -
  145.36 -  public NNTPDaemon(boolean aux) throws IOException
  145.37 -  {
  145.38 -    int port; 
  145.39 -    if(!aux)
  145.40 -      port = Config.getInstance().get("n3tpd.port", 119);
  145.41 -    else
  145.42 -      port = Config.getInstance().get("n3tpd.auxport", 8080);
  145.43 -    
  145.44 -    int backlog = Config.getInstance().get("n3tpd.server.backlog", 10);
  145.45 -    
  145.46 -    // Create and bind the socket
  145.47 -    socket = new ServerSocket(port, backlog);
  145.48 -  }
  145.49 -
  145.50 -  @Override
  145.51 -  public void run()
  145.52 -  {
  145.53 -    System.out.println("Daemon listening on port " + socket.getLocalPort() + " ...");
  145.54 -    
  145.55 -    while(isAlive() && !isInterrupted())
  145.56 -    {
  145.57 -      try
  145.58 -      {
  145.59 -        new NNTPConnection(socket.accept()).start();
  145.60 -      }
  145.61 -      catch (Exception e)
  145.62 -      {
  145.63 -        e.printStackTrace();
  145.64 -      }
  145.65 -    }
  145.66 -  }
  145.67 -}
   146.1 --- a/trunk/com/so/news/command/ArticleCommand.java	Tue Jan 20 10:21:03 2009 +0100
   146.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   146.3 @@ -1,124 +0,0 @@
   146.4 -/*
   146.5 - *   StarOffice News Server
   146.6 - *   see AUTHORS for the list of contributors
   146.7 - *
   146.8 - *   This program is free software: you can redistribute it and/or modify
   146.9 - *   it under the terms of the GNU General Public License as published by
  146.10 - *   the Free Software Foundation, either version 3 of the License, or
  146.11 - *   (at your option) any later version.
  146.12 - *
  146.13 - *   This program is distributed in the hope that it will be useful,
  146.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  146.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  146.16 - *   GNU General Public License for more details.
  146.17 - *
  146.18 - *   You should have received a copy of the GNU General Public License
  146.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  146.20 - */
  146.21 -
  146.22 -package com.so.news.command;
  146.23 -
  146.24 -import java.io.IOException;
  146.25 -import java.text.SimpleDateFormat;
  146.26 -import java.util.Locale;
  146.27 -import java.util.Map;
  146.28 -import com.so.news.Debug;
  146.29 -import com.so.news.NNTPConnection;
  146.30 -import com.so.news.storage.Article;
  146.31 -
  146.32 -/**
  146.33 - * Class handling the ARTICLE command.
  146.34 - * @author Christian Lins
  146.35 - * @author Dennis Schwerdel
  146.36 - */
  146.37 -public class ArticleCommand extends Command
  146.38 -{
  146.39 -  public ArticleCommand(NNTPConnection connection)
  146.40 -  {
  146.41 -    super(connection);
  146.42 -  }
  146.43 -
  146.44 -  public boolean process(String[] command) throws IOException
  146.45 -  {
  146.46 -    String commandName = command[0];
  146.47 -
  146.48 -    // untested, RFC977 compliant
  146.49 -    Article article = null;
  146.50 -    if (command.length <= 1)
  146.51 -    {
  146.52 -      article = getCurrentArticle();
  146.53 -      if (article == null)
  146.54 -      {
  146.55 -        printStatus(420, "no current article has been selected");
  146.56 -        return true;
  146.57 -      }
  146.58 -    }
  146.59 -    else if (command[1].matches(NNTPConnection.MESSAGE_ID_PATTERN))
  146.60 -    {
  146.61 -      // Message-ID
  146.62 -      article = Article.getByMessageID(command[1]);
  146.63 -      if (article == null)
  146.64 -      {
  146.65 -        printStatus(430, "no such article found");
  146.66 -        return true;
  146.67 -      }
  146.68 -    }
  146.69 -    else
  146.70 -    {
  146.71 -      // Message Number
  146.72 -      try
  146.73 -      {
  146.74 -        int num = Integer.parseInt(command[1]);
  146.75 -        article = Article.getByNumberInGroup(connection.getCurrentGroup(), num);
  146.76 -      }
  146.77 -      catch (Exception ex)
  146.78 -      {
  146.79 -        ex.printStackTrace(Debug.getInstance().getStream());
  146.80 -        System.err.println(ex.getLocalizedMessage());
  146.81 -      }
  146.82 -      if (article == null)
  146.83 -      {
  146.84 -        printStatus(423, "no such article number in this group");
  146.85 -        return true;
  146.86 -      }
  146.87 -      setCurrentArticle(article);
  146.88 -    }
  146.89 -
  146.90 -    if (commandName.equalsIgnoreCase("ARTICLE"))
  146.91 -    {
  146.92 -      printStatus(220, article.getNumberInGroup() + " " + article.getMessageID()
  146.93 -          + " article retrieved - head and body follow");
  146.94 -      Map<String, String> header = article.getHeader();
  146.95 -      for(Map.Entry<String, String> entry : header.entrySet())
  146.96 -      {
  146.97 -        if(entry.getKey().equals("Date"))
  146.98 -        {
  146.99 -          SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
 146.100 -          printTextPart("Date: " + sdf.format(article.getDate()));
 146.101 -        }
 146.102 -        else
 146.103 -          printTextPart(entry.getKey() + ": " + entry.getValue());
 146.104 -      }
 146.105 -      println("");
 146.106 -      printText(article.getBody());
 146.107 -    }
 146.108 -    else if (commandName.equalsIgnoreCase("HEAD"))
 146.109 -    {
 146.110 -      printStatus(500, "No longer supported! Use XOVER instead.");
 146.111 -      return false;
 146.112 -    }
 146.113 -    else if (commandName.equalsIgnoreCase("BODY"))
 146.114 -    {
 146.115 -      printStatus(222, article.getNumberInGroup() + " " + article.getMessageID()
 146.116 -          + " body");
 146.117 -      printText(article.getBody());
 146.118 -    }
 146.119 -    else if (commandName.equalsIgnoreCase("STAT"))
 146.120 -    {
 146.121 -      printStatus(223, article.getNumberInGroup() + " " + article.getMessageID()
 146.122 -          + " article retrieved - request text separately");
 146.123 -    }
 146.124 -    return true;
 146.125 -  }
 146.126 -
 146.127 -}
   147.1 --- a/trunk/com/so/news/command/CapabilitiesCommand.java	Tue Jan 20 10:21:03 2009 +0100
   147.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   147.3 @@ -1,50 +0,0 @@
   147.4 -/*
   147.5 - *   StarOffice News Server
   147.6 - *   see AUTHORS for the list of contributors
   147.7 - *
   147.8 - *   This program is free software: you can redistribute it and/or modify
   147.9 - *   it under the terms of the GNU General Public License as published by
  147.10 - *   the Free Software Foundation, either version 3 of the License, or
  147.11 - *   (at your option) any later version.
  147.12 - *
  147.13 - *   This program is distributed in the hope that it will be useful,
  147.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  147.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  147.16 - *   GNU General Public License for more details.
  147.17 - *
  147.18 - *   You should have received a copy of the GNU General Public License
  147.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  147.20 - */
  147.21 -
  147.22 -package com.so.news.command;
  147.23 -
  147.24 -import com.so.news.NNTPConnection;
  147.25 -
  147.26 -/**
  147.27 - *   The CAPABILITIES command allows a client to determine the
  147.28 -   capabilities of the server at any given time.
  147.29 -
  147.30 -   This command MAY be issued at any time; the server MUST NOT require
  147.31 -   it to be issued in order to make use of any capability.  The response
  147.32 -   generated by this command MAY change during a session because of
  147.33 -   other state information (which, in turn, may be changed by the
  147.34 -   effects of other commands or by external events).  An NNTP client is
  147.35 -   only able to get the current and correct information concerning
  147.36 -   available capabilities at any point during a session by issuing a
  147.37 -   CAPABILITIES command at that point of that session and processing the
  147.38 -   response.
  147.39 - * @author chris
  147.40 - */
  147.41 -public class CapabilitiesCommand extends Command
  147.42 -{
  147.43 -  public CapabilitiesCommand(NNTPConnection connection)
  147.44 -  {
  147.45 -    super(connection);
  147.46 -  }
  147.47 -  
  147.48 -  public boolean process(String[] command)
  147.49 -    throws Exception
  147.50 -  {
  147.51 -    return false;
  147.52 -  }
  147.53 -}
   148.1 --- a/trunk/com/so/news/command/Command.java	Tue Jan 20 10:21:03 2009 +0100
   148.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   148.3 @@ -1,106 +0,0 @@
   148.4 -/*
   148.5 - *   StarOffice News Server
   148.6 - *   see AUTHORS for the list of contributors
   148.7 - *
   148.8 - *   This program is free software: you can redistribute it and/or modify
   148.9 - *   it under the terms of the GNU General Public License as published by
  148.10 - *   the Free Software Foundation, either version 3 of the License, or
  148.11 - *   (at your option) any later version.
  148.12 - *
  148.13 - *   This program is distributed in the hope that it will be useful,
  148.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  148.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  148.16 - *   GNU General Public License for more details.
  148.17 - *
  148.18 - *   You should have received a copy of the GNU General Public License
  148.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  148.20 - */
  148.21 -
  148.22 -package com.so.news.command;
  148.23 -
  148.24 -import java.io.IOException;
  148.25 -import java.util.List;
  148.26 -import com.so.news.NNTPConnection;
  148.27 -import com.so.news.storage.Article;
  148.28 -import com.so.news.storage.Group;
  148.29 -
  148.30 -/**
  148.31 - * Base class for all command handling classes.
  148.32 - * @author Christian Lins
  148.33 - * @author Dennis Schwerdel
  148.34 - */
  148.35 -public abstract class Command
  148.36 -{
  148.37 -  protected NNTPConnection connection;
  148.38 -
  148.39 -  public Command(NNTPConnection connection)
  148.40 -  {
  148.41 -    this.connection = connection;
  148.42 -  }
  148.43 -
  148.44 -  protected static String NEWLINE = NNTPConnection.NEWLINE;
  148.45 -
  148.46 -  protected List<String> readText() 
  148.47 -    throws IOException
  148.48 -  {
  148.49 -    return connection.readText();
  148.50 -  }
  148.51 -
  148.52 -  protected String readTextLine() throws IOException
  148.53 -  {
  148.54 -    return connection.readTextLine();
  148.55 -  }
  148.56 -
  148.57 -  protected void printStatus(int status, String text) throws IOException
  148.58 -  {
  148.59 -    connection.printStatus(status, text);
  148.60 -  }
  148.61 -
  148.62 -  protected void printTextLine(CharSequence text) throws IOException
  148.63 -  {
  148.64 -    connection.printTextLine(text);
  148.65 -  }
  148.66 -
  148.67 -  protected void printTextPart(CharSequence text) throws IOException
  148.68 -  {
  148.69 -    connection.printTextPart(text);
  148.70 -  }
  148.71 -  
  148.72 -  protected void printText(CharSequence text) throws IOException
  148.73 -  {
  148.74 -    connection.printText(text);
  148.75 -  }
  148.76 -
  148.77 -  protected void println(CharSequence text) throws IOException
  148.78 -  {
  148.79 -    connection.println(text);
  148.80 -  }
  148.81 -
  148.82 -  protected void flush() throws IOException
  148.83 -  {
  148.84 -    connection.flush();
  148.85 -  }
  148.86 -
  148.87 -  protected Article getCurrentArticle()
  148.88 -  {
  148.89 -    return connection.getCurrentArticle();
  148.90 -  }
  148.91 -
  148.92 -  protected Group getCurrentGroup()
  148.93 -  {
  148.94 -    return connection.getCurrentGroup();
  148.95 -  }
  148.96 -
  148.97 -  protected void setCurrentArticle(Article current)
  148.98 -  {
  148.99 -    connection.setCurrentArticle(current);
 148.100 -  }
 148.101 -
 148.102 -  protected void setCurrentGroup(Group current)
 148.103 -  {
 148.104 -    connection.setCurrentGroup(current);
 148.105 -  }
 148.106 -
 148.107 -  public abstract boolean process(String[] command)
 148.108 -    throws Exception;
 148.109 -}
   149.1 --- a/trunk/com/so/news/command/GroupCommand.java	Tue Jan 20 10:21:03 2009 +0100
   149.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   149.3 @@ -1,60 +0,0 @@
   149.4 -/*
   149.5 - *   StarOffice News Server
   149.6 - *   see AUTHORS for the list of contributors
   149.7 - *
   149.8 - *   This program is free software: you can redistribute it and/or modify
   149.9 - *   it under the terms of the GNU General Public License as published by
  149.10 - *   the Free Software Foundation, either version 3 of the License, or
  149.11 - *   (at your option) any later version.
  149.12 - *
  149.13 - *   This program is distributed in the hope that it will be useful,
  149.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  149.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  149.16 - *   GNU General Public License for more details.
  149.17 - *
  149.18 - *   You should have received a copy of the GNU General Public License
  149.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  149.20 - */
  149.21 -
  149.22 -package com.so.news.command;
  149.23 -
  149.24 -import com.so.news.NNTPConnection;
  149.25 -import com.so.news.storage.Group;
  149.26 -
  149.27 -/**
  149.28 - * Class handling the GROUP command.
  149.29 - * @author Christian Lins
  149.30 - * @author Dennis Schwerdel
  149.31 - */
  149.32 -public class GroupCommand extends Command
  149.33 -{
  149.34 -  public GroupCommand(NNTPConnection conn)
  149.35 -  {
  149.36 -    super(conn);
  149.37 -  }
  149.38 -
  149.39 -  public boolean process(String[] command) 
  149.40 -    throws Exception
  149.41 -  {
  149.42 -    // untested, RFC977 compliant
  149.43 -    Group g = null;
  149.44 -    if (command.length >= 2)
  149.45 -    {
  149.46 -      g = Group.getByName(command[1]);
  149.47 -    }
  149.48 -    if (g == null)
  149.49 -    {
  149.50 -      printStatus(411, "no such news group");
  149.51 -      return true;
  149.52 -    }
  149.53 -    else
  149.54 -    {
  149.55 -      setCurrentGroup(g);
  149.56 -
  149.57 -      printStatus(211, g.getEstimatedArticleCount() + " " + g.getFirstArticle()
  149.58 -          + " " + g.getLastArticle() + " " + g.getName() + " group selected");
  149.59 -      return true;
  149.60 -    }
  149.61 -  }
  149.62 -
  149.63 -}
   150.1 --- a/trunk/com/so/news/command/ListCommand.java	Tue Jan 20 10:21:03 2009 +0100
   150.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   150.3 @@ -1,92 +0,0 @@
   150.4 -/*
   150.5 - *   StarOffice News Server
   150.6 - *   see AUTHORS for the list of contributors
   150.7 - *
   150.8 - *   This program is free software: you can redistribute it and/or modify
   150.9 - *   it under the terms of the GNU General Public License as published by
  150.10 - *   the Free Software Foundation, either version 3 of the License, or
  150.11 - *   (at your option) any later version.
  150.12 - *
  150.13 - *   This program is distributed in the hope that it will be useful,
  150.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  150.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  150.16 - *   GNU General Public License for more details.
  150.17 - *
  150.18 - *   You should have received a copy of the GNU General Public License
  150.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  150.20 - */
  150.21 -
  150.22 -package com.so.news.command;
  150.23 -
  150.24 -import java.io.IOException;
  150.25 -import java.util.ArrayList;
  150.26 -import com.so.news.NNTPConnection;
  150.27 -import com.so.news.storage.Group;
  150.28 -
  150.29 -/**
  150.30 - * Class handling the LIST command.
  150.31 - * @author Christian Lins
  150.32 - * @author Dennis Schwerdel
  150.33 - */
  150.34 -public class ListCommand extends Command
  150.35 -{
  150.36 -  public ListCommand(NNTPConnection conn)
  150.37 -  {
  150.38 -    super(conn);
  150.39 -  }
  150.40 -
  150.41 -  public boolean process(String[] command) 
  150.42 -    throws Exception
  150.43 -  {
  150.44 -    if (command.length >= 2)
  150.45 -    {
  150.46 -      if (command[1].equalsIgnoreCase("OVERVIEW.FMT"))
  150.47 -      {
  150.48 -        printStatus(215, "information follows");
  150.49 -        printText("Subject:\nFrom:\nDate:\nMessage-ID:\nReferences:\nBytes:\nLines:");
  150.50 -        return true;
  150.51 -      }
  150.52 -      if (command[1].equalsIgnoreCase("NEWSGROUPS"))
  150.53 -      {
  150.54 -        printStatus(215, "information follows");
  150.55 -        ArrayList<Group> list = Group.getAll();
  150.56 -        for (Group g : list)
  150.57 -        {
  150.58 -          printTextLine(g.getName() + "\t" + "-");
  150.59 -        }
  150.60 -        println(".");
  150.61 -        flush();
  150.62 -        return true;
  150.63 -      }
  150.64 -      if (command[1].equalsIgnoreCase("SUBSCRIPTIONS"))
  150.65 -      {
  150.66 -        printStatus(215, "information follows");
  150.67 -        println(".");
  150.68 -        flush();
  150.69 -        return true;
  150.70 -      }
  150.71 -      if (command[1].equalsIgnoreCase("EXTENSIONS"))
  150.72 -      {
  150.73 -        printStatus(202, "Supported NNTP extensions.");
  150.74 -        printTextLine("LISTGROUP");
  150.75 -        println(".");
  150.76 -        flush();
  150.77 -        return true;
  150.78 -      }
  150.79 -      return false;
  150.80 -    }
  150.81 -    printStatus(215, "list of newsgroups follows");
  150.82 -    for (Group g : Group.getAll())
  150.83 -    {
  150.84 -      //if(g.getEstimatedArticleCount() <= 0)
  150.85 -      //  continue;
  150.86 -      
  150.87 -      printTextLine(g.getName() + " " + g.getLastArticle() + " "
  150.88 -          + g.getFirstArticle() + " y");
  150.89 -    }
  150.90 -    println(".");
  150.91 -    flush();
  150.92 -    return true;
  150.93 -  }
  150.94 -
  150.95 -}
   151.1 --- a/trunk/com/so/news/command/ListGroupCommand.java	Tue Jan 20 10:21:03 2009 +0100
   151.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   151.3 @@ -1,71 +0,0 @@
   151.4 -/*
   151.5 - *   StarOffice News Server
   151.6 - *   see AUTHORS for the list of contributors
   151.7 - *
   151.8 - *   This program is free software: you can redistribute it and/or modify
   151.9 - *   it under the terms of the GNU General Public License as published by
  151.10 - *   the Free Software Foundation, either version 3 of the License, or
  151.11 - *   (at your option) any later version.
  151.12 - *
  151.13 - *   This program is distributed in the hope that it will be useful,
  151.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  151.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  151.16 - *   GNU General Public License for more details.
  151.17 - *
  151.18 - *   You should have received a copy of the GNU General Public License
  151.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  151.20 - */
  151.21 -
  151.22 -package com.so.news.command;
  151.23 -
  151.24 -import java.util.List;
  151.25 -import com.so.news.NNTPConnection;
  151.26 -import com.so.news.storage.Article;
  151.27 -import com.so.news.storage.Group;
  151.28 -
  151.29 -/**
  151.30 - * Class handling the LISTGROUP command.
  151.31 - * @author Christian Lins
  151.32 - * @author Dennis Schwerdel
  151.33 - */
  151.34 -public class ListGroupCommand extends Command
  151.35 -{
  151.36 -  public ListGroupCommand(NNTPConnection conn)
  151.37 -  {
  151.38 -    super(conn);
  151.39 -  }
  151.40 -
  151.41 -  public boolean process(String[] command) 
  151.42 -    throws Exception
  151.43 -  {
  151.44 -    String commandName = command[0];
  151.45 -    if (!commandName.equalsIgnoreCase("LISTGROUP"))
  151.46 -      return false;
  151.47 -    // untested, RFC977 complient
  151.48 -    Group group = null;
  151.49 -    if (command.length >= 2)
  151.50 -    {
  151.51 -      group = Group.getByName(command[1]);
  151.52 -    }
  151.53 -    else
  151.54 -    {
  151.55 -      group = getCurrentGroup();
  151.56 -    }
  151.57 -    if (group == null)
  151.58 -    {
  151.59 -      printStatus(412, "Not currently in newsgroup");
  151.60 -      return true;
  151.61 -    }
  151.62 -    List<Article> list = group.getAllArticles();
  151.63 -    printStatus(211, "list of article numbers follow"); // argh, bad english in
  151.64 -    // RFC
  151.65 -    for (Article a : list)
  151.66 -    {
  151.67 -      printTextLine("" + a.getNumberInGroup());
  151.68 -    }
  151.69 -    println(".");
  151.70 -    flush();
  151.71 -    return true;
  151.72 -  }
  151.73 -
  151.74 -}
   152.1 --- a/trunk/com/so/news/command/NewGroupsCommand.java	Tue Jan 20 10:21:03 2009 +0100
   152.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   152.3 @@ -1,68 +0,0 @@
   152.4 -/*
   152.5 - *   StarOffice News Server
   152.6 - *   see AUTHORS for the list of contributors
   152.7 - *
   152.8 - *   This program is free software: you can redistribute it and/or modify
   152.9 - *   it under the terms of the GNU General Public License as published by
  152.10 - *   the Free Software Foundation, either version 3 of the License, or
  152.11 - *   (at your option) any later version.
  152.12 - *
  152.13 - *   This program is distributed in the hope that it will be useful,
  152.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  152.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  152.16 - *   GNU General Public License for more details.
  152.17 - *
  152.18 - *   You should have received a copy of the GNU General Public License
  152.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  152.20 - */
  152.21 -
  152.22 -package com.so.news.command;
  152.23 -
  152.24 -import java.io.IOException;
  152.25 -import java.util.ArrayList;
  152.26 -import com.so.news.NNTPConnection;
  152.27 -import com.so.news.storage.Group;
  152.28 -
  152.29 -/**
  152.30 - * Class handling the NEWGROUPS command.
  152.31 - * @author Christian Lins
  152.32 - * @author Dennis Schwerdel
  152.33 - */
  152.34 -public class NewGroupsCommand extends Command
  152.35 -{
  152.36 -  public NewGroupsCommand(NNTPConnection conn)
  152.37 -  {
  152.38 -    super(conn);
  152.39 -  }
  152.40 -
  152.41 -  public boolean process(String[] command) throws IOException
  152.42 -  {
  152.43 -    String commandName = command[0];
  152.44 -    if (!commandName.equalsIgnoreCase("NEWGROUPS"))
  152.45 -      return false;
  152.46 -    if (command.length != 3)
  152.47 -      return false;
  152.48 -    // untested, not RFC977 complient
  152.49 -    try
  152.50 -    {
  152.51 -      // Timestamp date = new Timestamp ( new SimpleDateFormat ("yyMMdd
  152.52 -      // HHmmss").parse(command[1] + " " + command[2] ).getTime()) ;
  152.53 -      printStatus(231, "list of new newsgroups follows");
  152.54 -      ArrayList<Group> list = Group.getAll();// (date) ;
  152.55 -      for (Group g : list)
  152.56 -      {
  152.57 -        printTextLine(g.getName() + " " + g.getLastArticle() + " "
  152.58 -            + g.getFirstArticle() + " y");
  152.59 -      }
  152.60 -      println(".");
  152.61 -      flush();
  152.62 -      return true;
  152.63 -    }
  152.64 -    catch (Exception e)
  152.65 -    {
  152.66 -      printStatus(511, "listing failed - invalid date format");
  152.67 -      return true;
  152.68 -    }
  152.69 -  }
  152.70 -
  152.71 -}
   153.1 --- a/trunk/com/so/news/command/NextCommand.java	Tue Jan 20 10:21:03 2009 +0100
   153.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   153.3 @@ -1,82 +0,0 @@
   153.4 -/*
   153.5 - *   StarOffice News Server
   153.6 - *   see AUTHORS for the list of contributors
   153.7 - *
   153.8 - *   This program is free software: you can redistribute it and/or modify
   153.9 - *   it under the terms of the GNU General Public License as published by
  153.10 - *   the Free Software Foundation, either version 3 of the License, or
  153.11 - *   (at your option) any later version.
  153.12 - *
  153.13 - *   This program is distributed in the hope that it will be useful,
  153.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  153.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  153.16 - *   GNU General Public License for more details.
  153.17 - *
  153.18 - *   You should have received a copy of the GNU General Public License
  153.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  153.20 - */
  153.21 -
  153.22 -package com.so.news.command;
  153.23 -
  153.24 -import java.io.IOException;
  153.25 -import com.so.news.NNTPConnection;
  153.26 -import com.so.news.storage.Article;
  153.27 -import com.so.news.storage.Group;
  153.28 -
  153.29 -/**
  153.30 - * Class handling the NEXT and LAST command.
  153.31 - * @author Christian Lins
  153.32 - * @author Dennis Schwerdel
  153.33 - */
  153.34 -public class NextCommand extends Command
  153.35 -{
  153.36 -  public NextCommand(NNTPConnection conn)
  153.37 -  {
  153.38 -    super(conn);
  153.39 -  }
  153.40 -
  153.41 -  public boolean process(String[] command) throws IOException
  153.42 -  {
  153.43 -    String commandName = command[0];
  153.44 -    if (!(commandName.equalsIgnoreCase("NEXT") || commandName
  153.45 -        .equalsIgnoreCase("LAST")))
  153.46 -      return false;
  153.47 -    // untested, RFC977 complient
  153.48 -    Article currA = getCurrentArticle();
  153.49 -    Group currG = getCurrentGroup();
  153.50 -    if (currA == null)
  153.51 -    {
  153.52 -      printStatus(420, "no current article has been selected");
  153.53 -      return true;
  153.54 -    }
  153.55 -    if (currG == null)
  153.56 -    {
  153.57 -      printStatus(412, "no newsgroup selected");
  153.58 -      return true;
  153.59 -    }
  153.60 -    Article article;
  153.61 -    if (commandName.equalsIgnoreCase("NEXT"))
  153.62 -    {
  153.63 -      article = currA.nextArticleInGroup();
  153.64 -      if (article == null)
  153.65 -      {
  153.66 -        printStatus(421, "no next article in this group");
  153.67 -        return true;
  153.68 -      }
  153.69 -    }
  153.70 -    else
  153.71 -    {
  153.72 -      article = currA.prevArticleInGroup();
  153.73 -      if (article == null)
  153.74 -      {
  153.75 -        printStatus(422, "no previous article in this group");
  153.76 -        return true;
  153.77 -      }
  153.78 -    }
  153.79 -    setCurrentArticle(article);
  153.80 -    printStatus(223, article.getNumberInGroup() + " " + article.getMessageID()
  153.81 -        + " article retrieved - request text separately");
  153.82 -    return true;
  153.83 -  }
  153.84 -
  153.85 -}
   154.1 --- a/trunk/com/so/news/command/OverCommand.java	Tue Jan 20 10:21:03 2009 +0100
   154.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   154.3 @@ -1,183 +0,0 @@
   154.4 -/*
   154.5 - *   StarOffice News Server
   154.6 - *   see AUTHORS for the list of contributors
   154.7 - *
   154.8 - *   This program is free software: you can redistribute it and/or modify
   154.9 - *   it under the terms of the GNU General Public License as published by
  154.10 - *   the Free Software Foundation, either version 3 of the License, or
  154.11 - *   (at your option) any later version.
  154.12 - *
  154.13 - *   This program is distributed in the hope that it will be useful,
  154.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  154.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  154.16 - *   GNU General Public License for more details.
  154.17 - *
  154.18 - *   You should have received a copy of the GNU General Public License
  154.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  154.20 - */
  154.21 -
  154.22 -package com.so.news.command;
  154.23 -
  154.24 -import java.text.SimpleDateFormat;
  154.25 -import java.util.Locale;
  154.26 -
  154.27 -import com.so.news.Debug;
  154.28 -import com.so.news.NNTPConnection;
  154.29 -import com.so.news.storage.Article;
  154.30 -
  154.31 -/**
  154.32 - * Class handling the OVER/XOVER command.
  154.33 - * 
  154.34 - * Description of the XOVER command:
  154.35 - * 
  154.36 - * XOVER [range]
  154.37 - *
  154.38 - * The XOVER command returns information from the overview
  154.39 - * database for the article(s) specified.
  154.40 - *
  154.41 - * The optional range argument may be any of the following:
  154.42 - *              an article number
  154.43 - *              an article number followed by a dash to indicate
  154.44 - *                 all following
  154.45 - *              an article number followed by a dash followed by
  154.46 - *                 another article number
  154.47 - *
  154.48 - * If no argument is specified, then information from the
  154.49 - * current article is displayed. Successful responses start
  154.50 - * with a 224 response followed by the overview information
  154.51 - * for all matched messages. Once the output is complete, a
  154.52 - * period is sent on a line by itself. If no argument is
  154.53 - * specified, the information for the current article is
  154.54 - * returned.  A news group must have been selected earlier,
  154.55 - * else a 412 error response is returned. If no articles are
  154.56 - * in the range specified, a 420 error response is returned
  154.57 - * by the server. A 502 response will be returned if the
  154.58 - * client only has permission to transfer articles.
  154.59 - *
  154.60 - * Each line of output will be formatted with the article number,
  154.61 - * followed by each of the headers in the overview database or the
  154.62 - * article itself (when the data is not available in the overview
  154.63 - * database) for that article separated by a tab character.  The
  154.64 - * sequence of fields must be in this order: subject, author,
  154.65 - * date, message-id, references, byte count, and line count. Other
  154.66 - * optional fields may follow line count. Other optional fields may
  154.67 - * follow line count. These fields are specified by examining the
  154.68 - * response to the LIST OVERVIEW.FMT command. Where no data exists,
  154.69 - * a null field must be provided (i.e. the output will have two tab
  154.70 - * characters adjacent to each other). Servers should not output
  154.71 - * fields for articles that have been removed since the XOVER database
  154.72 - * was created.
  154.73 - *
  154.74 - * The LIST OVERVIEW.FMT command should be implemented if XOVER
  154.75 - * is implemented. A client can use LIST OVERVIEW.FMT to determine
  154.76 - * what optional fields  and in which order all fields will be
  154.77 - * supplied by the XOVER command. 
  154.78 - *
  154.79 - * Note that any tab and end-of-line characters in any header
  154.80 - * data that is returned will be converted to a space character.
  154.81 - *
  154.82 - * Responses:
  154.83 - *
  154.84 - *   224 Overview information follows
  154.85 - *   412 No news group current selected
  154.86 - *   420 No article(s) selected
  154.87 - *   502 no permission
  154.88 - * 
  154.89 - * @author Christian Lins
  154.90 - */
  154.91 -public class OverCommand extends Command
  154.92 -{
  154.93 -  public OverCommand(NNTPConnection conn)
  154.94 -  {
  154.95 -    super(conn);
  154.96 -  }
  154.97 -  
  154.98 -  public boolean process(String[] command)
  154.99 -    throws Exception
 154.100 -  {
 154.101 -    if(getCurrentGroup() == null)
 154.102 -    {
 154.103 -      printStatus(412, "No news group current selected");
 154.104 -      return false;
 154.105 -    }
 154.106 -    
 154.107 -    // If no parameter was specified, show information about
 154.108 -    // the currently selected article(s)
 154.109 -    if(command.length == 1)
 154.110 -    {
 154.111 -      Article art = getCurrentArticle();
 154.112 -      if(art == null)
 154.113 -      {
 154.114 -        printStatus(420, "No article(s) selected");
 154.115 -        return false;
 154.116 -      }
 154.117 -      
 154.118 -      String o = buildOverview(art, -1);
 154.119 -      printText(o);
 154.120 -    }
 154.121 -    // otherwise print information about the specified range
 154.122 -    else
 154.123 -    {
 154.124 -      int artStart = -1;
 154.125 -      int artEnd   = -1;
 154.126 -      String[] nums = command[1].split("-");
 154.127 -      if(nums.length > 1)
 154.128 -      {
 154.129 -        try
 154.130 -        {
 154.131 -          artStart = Integer.parseInt(nums[0]);
 154.132 -        }
 154.133 -        catch(Exception e) 
 154.134 -        {
 154.135 -          artStart = Integer.parseInt(command[1]);
 154.136 -        }
 154.137 -        try
 154.138 -        {
 154.139 -          artEnd = Integer.parseInt(nums[1]);
 154.140 -        }
 154.141 -        catch(Exception e) {}
 154.142 -      }
 154.143 -
 154.144 -      printStatus(224, "Overview information follows");
 154.145 -      for(int n = artStart; n <= artEnd; n++)
 154.146 -      {
 154.147 -        Article art = Article.getByNumberInGroup(getCurrentGroup(), n);
 154.148 -        if(art == null)
 154.149 -        {
 154.150 -          Debug.getInstance().log("Article (gid=" + getCurrentGroup() + ", art=" + n + " is null!");
 154.151 -        }
 154.152 -        else
 154.153 -        {
 154.154 -          printTextPart(buildOverview(art, n) + NEWLINE);
 154.155 -        }
 154.156 -      }
 154.157 -      println(".");
 154.158 -      flush();
 154.159 -    }
 154.160 -    
 154.161 -    return true;
 154.162 -  }
 154.163 -  
 154.164 -  private String buildOverview(Article art, int nr)
 154.165 -  {
 154.166 -    SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
 154.167 -    StringBuilder overview = new StringBuilder();
 154.168 -    overview.append(nr);
 154.169 -    overview.append('\t');
 154.170 -    overview.append(art.getHeader().get("Subject"));
 154.171 -    overview.append('\t');
 154.172 -    overview.append(art.getHeader().get("From"));
 154.173 -    overview.append('\t');
 154.174 -    overview.append(sdf.format(art.getDate()));
 154.175 -    overview.append('\t');
 154.176 -    overview.append(art.getHeader().get("Message-ID"));
 154.177 -    overview.append('\t');
 154.178 -    overview.append(art.getHeader().get("References"));
 154.179 -    overview.append('\t');
 154.180 -    overview.append(art.getHeader().get("Bytes"));
 154.181 -    overview.append('\t');
 154.182 -    overview.append(art.getHeader().get("Lines"));
 154.183 -    
 154.184 -    return overview.toString();
 154.185 -  }
 154.186 -}
   155.1 --- a/trunk/com/so/news/command/PostCommand.java	Tue Jan 20 10:21:03 2009 +0100
   155.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   155.3 @@ -1,166 +0,0 @@
   155.4 -/*
   155.5 - *   StarOffice News Server
   155.6 - *   see AUTHORS for the list of contributors
   155.7 - *
   155.8 - *   This program is free software: you can redistribute it and/or modify
   155.9 - *   it under the terms of the GNU General Public License as published by
  155.10 - *   the Free Software Foundation, either version 3 of the License, or
  155.11 - *   (at your option) any later version.
  155.12 - *
  155.13 - *   This program is distributed in the hope that it will be useful,
  155.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  155.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  155.16 - *   GNU General Public License for more details.
  155.17 - *
  155.18 - *   You should have received a copy of the GNU General Public License
  155.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  155.20 - */
  155.21 -
  155.22 -package com.so.news.command;
  155.23 -
  155.24 -import java.io.IOException;
  155.25 -import java.sql.SQLException;
  155.26 -import java.util.Date;
  155.27 -import java.text.SimpleDateFormat;
  155.28 -import java.util.HashMap;
  155.29 -import java.util.Locale;
  155.30 -
  155.31 -import com.so.news.Config;
  155.32 -import com.so.news.Debug;
  155.33 -import com.so.news.NNTPConnection;
  155.34 -import com.so.news.storage.Article;
  155.35 -import com.so.news.storage.Database;
  155.36 -
  155.37 -/**
  155.38 - * Contains the code for the POST command.
  155.39 - * @author Christian Lins
  155.40 - * @author Dennis Schwerdel
  155.41 - */
  155.42 -public class PostCommand extends Command
  155.43 -{
  155.44 -  public PostCommand(NNTPConnection conn)
  155.45 -  {
  155.46 -    super(conn);
  155.47 -  }
  155.48 -
  155.49 -  public boolean process(String[] command) throws IOException
  155.50 -  {
  155.51 -    printStatus(340, "send article to be posted. End with <CR-LF>.<CR-LF>");
  155.52 -
  155.53 -    // some initialization
  155.54 -    Article article = new Article();
  155.55 -    int lineCount     = 0;
  155.56 -    long bodySize     = 0;
  155.57 -    long maxBodySize  = Config.getInstance().get("n3tpd.article.maxsize", 1024) * 1024; // Size in bytes
  155.58 -
  155.59 -    // begin with a stringbuilder body
  155.60 -    StringBuilder body = new StringBuilder();
  155.61 -    HashMap<String, String> header = new HashMap<String, String>();
  155.62 -
  155.63 -    boolean isHeader = true; // are we in the header part
  155.64 -
  155.65 -    String line = readTextLine();
  155.66 -    while(line != null)
  155.67 -    {
  155.68 -      bodySize += line.length();
  155.69 -      if(bodySize > maxBodySize)
  155.70 -      {
  155.71 -        printStatus(500, "article is too long");
  155.72 -        return false;
  155.73 -      }
  155.74 -
  155.75 -      if(!isHeader)
  155.76 -      { // body
  155.77 -        if(line.trim().equals("."))
  155.78 -          break;
  155.79 -        
  155.80 -        bodySize += line.length() + 1;
  155.81 -        lineCount++;
  155.82 -        body.append(line + NEWLINE);
  155.83 -      }
  155.84 -      
  155.85 -      if(line.equals(""))
  155.86 -      {
  155.87 -        isHeader = false; // we finally met the blank line
  155.88 -                          // separating headers from body
  155.89 -      }
  155.90 -
  155.91 -      if(isHeader)
  155.92 -      { // header
  155.93 -        // split name and value and add the header to the map
  155.94 -        int colon = line.indexOf(':');
  155.95 -        String fieldName = line.substring(0, colon).trim();
  155.96 -        String fieldValue = line.substring(colon + 1).trim();
  155.97 -        header.put(fieldName, fieldValue);
  155.98 -      }
  155.99 -      line = readTextLine(); // read a new line
 155.100 -    } // end of input reading
 155.101 -
 155.102 -    article.setBody(body.toString()); // set the article body
 155.103 -    article.setHeader(header);     // add the header entries for the article
 155.104 -    
 155.105 -    // Read the date header and fall back to the current date if it is not set
 155.106 -    try
 155.107 -    {
 155.108 -      SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
 155.109 -      String date = header.get("DATE");
 155.110 -      if(date == null)
 155.111 -        article.setDate(new Date());
 155.112 -      else
 155.113 -        article.setDate(new Date(sdf.parse(date).getTime())) ;
 155.114 -    }
 155.115 -    catch (Exception e)
 155.116 -    {
 155.117 -      e.printStackTrace(Debug.getInstance().getStream());
 155.118 -      printStatus(541, "posting failed - invalid date format");
 155.119 -      return true;
 155.120 -    }
 155.121 -
 155.122 -    // check for a cancel command
 155.123 -    if ( header.containsKey("Control") ) 
 155.124 -    {
 155.125 -      String[] control = header.get("Control").split(" ") ;
 155.126 -      if ( control.length >= 2 && control[0].equalsIgnoreCase("cancel") ) 
 155.127 -      {
 155.128 -        // this article is a cancel-article, try to delete the old article
 155.129 -        try
 155.130 -        {
 155.131 -          Article.getByMessageID(control[1]).delete();
 155.132 -          printStatus(240, "article posted ok - original article canceled"); // quite
 155.133 -          return true; // quit, do not actually post this article since it
 155.134 -        }
 155.135 -        catch (Exception e)
 155.136 -        {
 155.137 -          e.printStackTrace();
 155.138 -          printStatus(441, "posting failed - original posting not found");
 155.139 -          return true;
 155.140 -        }
 155.141 -      }
 155.142 -    }
 155.143 -
 155.144 -    // set some headers
 155.145 -    header.put("Message-ID", article.getMessageID());
 155.146 -    header.put("Lines", "" + lineCount);
 155.147 -    header.put("Bytes", "" + bodySize);
 155.148 -
 155.149 -    // if needed, set an empty references header, that means this is
 155.150 -    // a initial posting
 155.151 -    if (!header.containsKey("References"))
 155.152 -      header.put("References", "");
 155.153 -
 155.154 -    // try to create the article in the database
 155.155 -    try
 155.156 -    {
 155.157 -      Database.getInstance().addArticle(article);
 155.158 -      printStatus(240, "article posted ok");
 155.159 -    }
 155.160 -    catch(SQLException ex)
 155.161 -    {
 155.162 -      System.err.println(ex.getLocalizedMessage());
 155.163 -      ex.printStackTrace(Debug.getInstance().getStream());
 155.164 -      printStatus(500, "internal server error");
 155.165 -    }
 155.166 -
 155.167 -    return true;
 155.168 -  }
 155.169 -}
   156.1 --- a/trunk/com/so/news/io/Resource.java	Tue Jan 20 10:21:03 2009 +0100
   156.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   156.3 @@ -1,123 +0,0 @@
   156.4 -/*
   156.5 - *   StarOffice News Server
   156.6 - *   see AUTHORS for the list of contributors
   156.7 - *
   156.8 - *   This program is free software: you can redistribute it and/or modify
   156.9 - *   it under the terms of the GNU General Public License as published by
  156.10 - *   the Free Software Foundation, either version 3 of the License, or
  156.11 - *   (at your option) any later version.
  156.12 - *
  156.13 - *   This program is distributed in the hope that it will be useful,
  156.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  156.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  156.16 - *   GNU General Public License for more details.
  156.17 - *
  156.18 - *   You should have received a copy of the GNU General Public License
  156.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  156.20 - */
  156.21 -
  156.22 -package com.so.news.io;
  156.23 -
  156.24 -import java.io.BufferedReader;
  156.25 -import java.io.File;
  156.26 -import java.io.FileInputStream;
  156.27 -import java.io.IOException;
  156.28 -import java.io.InputStream;
  156.29 -import java.io.InputStreamReader;
  156.30 -import java.net.URL;
  156.31 -import java.nio.charset.Charset;
  156.32 -
  156.33 -/**
  156.34 - * Provides method for loading of resources.
  156.35 - * @author Christian Lins
  156.36 - */
  156.37 -public class Resource
  156.38 -{
  156.39 -  /**
  156.40 -   * Loads a file as array of byte. As the file is completely loaded into
  156.41 -   * memory this method should only be used with small files.
  156.42 -   * @param file
  156.43 -   * @return
  156.44 -   */
  156.45 -  public static byte[] getBytes(File file)
  156.46 -  {
  156.47 -    try
  156.48 -    {
  156.49 -      FileInputStream in = new FileInputStream(file);
  156.50 -      byte[] buffer = new byte[(int)file.length()];
  156.51 -      
  156.52 -      in.read(buffer);
  156.53 -      
  156.54 -      return buffer;
  156.55 -    }
  156.56 -    catch(IOException ex)
  156.57 -    {
  156.58 -      System.err.println(ex.getLocalizedMessage());
  156.59 -      return null;
  156.60 -    }
  156.61 -  }
  156.62 -  
  156.63 -  /**
  156.64 -   * Loads a resource and returns it as URL reference.
  156.65 -   * The Resource's classloader is used to load the resource, not
  156.66 -   * the System's ClassLoader so it may be safe to use this method
  156.67 -   * in a sandboxed environment.
  156.68 -   * @return
  156.69 -   */
  156.70 -  public static URL getAsURL(String name)
  156.71 -  {
  156.72 -    return Resource.class.getClassLoader().getResource(name);
  156.73 -  }
  156.74 -  
  156.75 -  /**
  156.76 -   * Loads a resource and returns an InputStream to it.
  156.77 -   * @param name
  156.78 -   * @return
  156.79 -   */
  156.80 -  public static InputStream getAsStream(String name)
  156.81 -  {
  156.82 -    try
  156.83 -    {
  156.84 -      URL url = getAsURL(name);
  156.85 -      return url.openStream();
  156.86 -    }
  156.87 -    catch(IOException e)
  156.88 -    {
  156.89 -      e.printStackTrace();
  156.90 -      return null;
  156.91 -    }
  156.92 -  }
  156.93 -
  156.94 -  /**
  156.95 -   * Loads a plain text resource.
  156.96 -   * @param withNewline If false all newlines are removed from the 
  156.97 -   * return String
  156.98 -   */
  156.99 -  public static String getAsString(String name, boolean withNewline)
 156.100 -  {
 156.101 -    try
 156.102 -    {
 156.103 -      BufferedReader in  = new BufferedReader(
 156.104 -          new InputStreamReader(getAsStream(name), Charset.forName("UTF-8")));
 156.105 -      StringBuffer   buf = new StringBuffer();
 156.106 -
 156.107 -      for(;;)
 156.108 -      {
 156.109 -        String line = in.readLine();
 156.110 -        if(line == null)
 156.111 -          break;
 156.112 -
 156.113 -        buf.append(line);
 156.114 -        if(withNewline)
 156.115 -          buf.append('\n');
 156.116 -      }
 156.117 -
 156.118 -      return buf.toString();
 156.119 -    }
 156.120 -    catch(Exception e)
 156.121 -    {
 156.122 -      e.printStackTrace();
 156.123 -      return null;
 156.124 -    }
 156.125 -  }
 156.126 -}
   157.1 --- a/trunk/com/so/news/storage/Article.java	Tue Jan 20 10:21:03 2009 +0100
   157.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   157.3 @@ -1,307 +0,0 @@
   157.4 -/*
   157.5 - *   StarOffice News Server
   157.6 - *   see AUTHORS for the list of contributors
   157.7 - *
   157.8 - *   This program is free software: you can redistribute it and/or modify
   157.9 - *   it under the terms of the GNU General Public License as published by
  157.10 - *   the Free Software Foundation, either version 3 of the License, or
  157.11 - *   (at your option) any later version.
  157.12 - *
  157.13 - *   This program is distributed in the hope that it will be useful,
  157.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  157.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  157.16 - *   GNU General Public License for more details.
  157.17 - *
  157.18 - *   You should have received a copy of the GNU General Public License
  157.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  157.20 - */
  157.21 -
  157.22 -package com.so.news.storage;
  157.23 -
  157.24 -import java.sql.ResultSet;
  157.25 -import java.sql.SQLException;
  157.26 -import java.util.Date;
  157.27 -import java.util.HashMap;
  157.28 -import java.util.Map;
  157.29 -import java.util.Map.Entry;
  157.30 -import java.util.UUID;
  157.31 -
  157.32 -import com.so.news.Config;
  157.33 -import com.so.news.Debug;
  157.34 -
  157.35 -/**
  157.36 - * Represents a newsgroup article.
  157.37 - * @author Christian Lins
  157.38 - * @author Denis Schwerdel
  157.39 - */
  157.40 -public class Article
  157.41 -{
  157.42 -  /**
  157.43 -   * Loads the Article identified by the given ID from the Database.
  157.44 -   * @param messageID
  157.45 -   * @return null if Article is not found or if an error occurred.
  157.46 -   */
  157.47 -  public static Article getByMessageID(String messageID)
  157.48 -  {
  157.49 -    try
  157.50 -    {
  157.51 -      return Database.getInstance().getArticle(messageID);
  157.52 -    }
  157.53 -    catch(SQLException ex)
  157.54 -    {
  157.55 -      ex.printStackTrace(Debug.getInstance().getStream());
  157.56 -      return null;
  157.57 -    }
  157.58 -  }
  157.59 -  
  157.60 -  public static Article getByNumberInGroup(Group group, int number)
  157.61 -    throws SQLException
  157.62 -  {
  157.63 -    long gid = group.getID(); 
  157.64 -    return Database.getInstance().getArticle(gid, number); // Is number her correct?
  157.65 -  }
  157.66 -  
  157.67 -  private String              body      = "";
  157.68 -  private long                groupID   = -1;
  157.69 -  private Map<String, String> header    = new HashMap<String, String>();
  157.70 -  private int                 numberInGroup = -1;
  157.71 -  private String              msgID     = null;
  157.72 -  
  157.73 -  /**
  157.74 -   * Default constructor.
  157.75 -   */
  157.76 -  public Article()
  157.77 -  {
  157.78 -  }
  157.79 -  
  157.80 -  /**
  157.81 -   * Creates a new Article object using the date from the given
  157.82 -   * ResultSet. It is expected that ResultSet.next() was already
  157.83 -   * called by the Database class.
  157.84 -   * This construction has only package visibility.
  157.85 -   * @param rs
  157.86 -   */
  157.87 -  Article(ResultSet rs)
  157.88 -    throws SQLException
  157.89 -  {
  157.90 -    this.body  = rs.getString("body");
  157.91 -    this.msgID = rs.getString("message_id");
  157.92 -    
  157.93 -    // Parse the header
  157.94 -    parseHeader(rs.getString("header"));
  157.95 -  }
  157.96 -  
  157.97 -  /**
  157.98 -   * Parses the header fields and puts them into a map for faster access.
  157.99 -   * TODO: There could be fields that go over more than one line, some
 157.100 -   * bad clients do create them.
 157.101 -   * @param hsrc
 157.102 -   */
 157.103 -  private void parseHeader(String hsrc)
 157.104 -  {
 157.105 -    String[] lines = hsrc.split("\n");
 157.106 -    
 157.107 -    for(String line : lines)
 157.108 -    {
 157.109 -      String[] kv = line.split(":");
 157.110 -      if(kv.length < 2)
 157.111 -      {
 157.112 -        Debug.getInstance().log("Invalid header field: " + line);
 157.113 -        continue;
 157.114 -      }
 157.115 -      else
 157.116 -      {
 157.117 -        // Set value in the header hash map
 157.118 -        String value = kv[1];
 157.119 -        for(int n = 2; n < kv.length; n++)
 157.120 -          value += ":" + kv[n];
 157.121 -        this.header.put(kv[0], value);
 157.122 -      }
 157.123 -    }
 157.124 -  }
 157.125 -  
 157.126 -  /**
 157.127 -   * Returnes the next Article in the group of this Article.
 157.128 -   * @return
 157.129 -   */
 157.130 -  public Article nextArticleInGroup()
 157.131 -  {
 157.132 -    return null;
 157.133 -  }
 157.134 -
 157.135 -  /**
 157.136 -   * Returns the previous Article in the group of this Article.
 157.137 -   * @return
 157.138 -   */
 157.139 -  public Article prevArticleInGroup()
 157.140 -  {
 157.141 -    return null;
 157.142 -  }
 157.143 -
 157.144 -  /**
 157.145 -   * Generates a message id for this article and sets it into
 157.146 -   * the header HashMap.
 157.147 -   */
 157.148 -  private String generateMessageID()
 157.149 -  {
 157.150 -    this.msgID = "<" + UUID.randomUUID() + "@"
 157.151 -        + Config.getInstance().get("n3tpd.hostname", "localhost") + ">";
 157.152 -    
 157.153 -    this.header.put("Message-ID", msgID);
 157.154 -    
 157.155 -    return msgID;
 157.156 -  }
 157.157 -
 157.158 -  /**
 157.159 -   * Tries to delete this article.
 157.160 -   * @return false if the article could not be deleted, otherwise true
 157.161 -   */
 157.162 -  public boolean delete()
 157.163 -  {
 157.164 -    return false;
 157.165 -  }
 157.166 -  
 157.167 -  /**
 157.168 -   * Checks if all necessary header fields are within this header.
 157.169 -   */
 157.170 -  private void validateHeader()
 157.171 -  {    
 157.172 -    // Forces a MessageID creation if not existing
 157.173 -    getMessageID();
 157.174 -    
 157.175 -    // Check if the references are correct...
 157.176 -    String rep = header.get("In-Reply-To");
 157.177 -    if(rep == null) // Some clients use only references instead of In-Reply-To
 157.178 -      return; //rep = header.get("References");
 157.179 -    
 157.180 -    String ref = getMessageID();
 157.181 -    
 157.182 -    if(rep != null && !rep.equals(""))
 157.183 -    {
 157.184 -      Article art = null; //TODO // getByMessageID(rep, articleDir);
 157.185 -      if(art != null)
 157.186 -      {
 157.187 -        ref = art.header.get("References") + " " + rep;
 157.188 -      }
 157.189 -    }
 157.190 -    header.put("References", ref);
 157.191 -  }
 157.192 -
 157.193 -  /**
 157.194 -   * Returns the body string.
 157.195 -   */
 157.196 -  public String getBody()
 157.197 -  {
 157.198 -    return body;
 157.199 -  }
 157.200 -  
 157.201 -  /**
 157.202 -   * @return Numerical ID of the associated Group.
 157.203 -   */
 157.204 -  long getGroupID()
 157.205 -  {
 157.206 -    if(groupID == -1) // If the GroupID was not determined yet
 157.207 -    {
 157.208 -      // Determining GroupID
 157.209 -      String   newsgroups = this.header.get("Newsgroups");
 157.210 -      if(newsgroups != null)
 157.211 -      {
 157.212 -        String[] newsgroup  = newsgroups.split(",");
 157.213 -        // Crossposting is not supported
 157.214 -        try
 157.215 -        {
 157.216 -          Group group;
 157.217 -          if(newsgroup.length > 0)
 157.218 -            group = Database.getInstance().getGroup(newsgroup[0].trim());
 157.219 -          else
 157.220 -            group = Database.getInstance().getGroup(newsgroups.trim());
 157.221 -          // TODO: What to do if Group does not exist?
 157.222 -          this.groupID = group.getID();
 157.223 -        }
 157.224 -        catch(SQLException ex)
 157.225 -        {
 157.226 -          ex.printStackTrace(Debug.getInstance().getStream());
 157.227 -          System.err.println(ex.getLocalizedMessage());
 157.228 -        }
 157.229 -      }
 157.230 -      else
 157.231 -        System.err.println("Should never happen: Article::getGroupID");
 157.232 -    }
 157.233 -    return this.groupID;
 157.234 -  }
 157.235 -
 157.236 -  public void setBody(String body)
 157.237 -  {
 157.238 -    this.body = body;
 157.239 -  }
 157.240 -
 157.241 -  public int getNumberInGroup()
 157.242 -  {
 157.243 -    return this.numberInGroup;
 157.244 -  }
 157.245 -  
 157.246 -  public void setHeader(HashMap<String, String> header)
 157.247 -  {
 157.248 -    this.header = header;
 157.249 -  }
 157.250 -
 157.251 -  public void setNumberInGroup(int id)
 157.252 -  {
 157.253 -    this.numberInGroup = id;
 157.254 -  }
 157.255 -
 157.256 -  public String getMessageID()
 157.257 -  {
 157.258 -    if(msgID == null)
 157.259 -      msgID = generateMessageID();
 157.260 -    return msgID;
 157.261 -  }
 157.262 -
 157.263 -  /**
 157.264 -   * @return Header source code of this Article.
 157.265 -   */
 157.266 -  public String getHeaderSource()
 157.267 -  {
 157.268 -    StringBuffer buf = new StringBuffer();
 157.269 -    
 157.270 -    for(Entry<String, String> entry : this.header.entrySet())
 157.271 -    {
 157.272 -      buf.append(entry.getKey());
 157.273 -      buf.append(":");
 157.274 -      buf.append(entry.getValue());
 157.275 -      buf.append("\n");
 157.276 -    }
 157.277 -    
 157.278 -    return buf.toString();
 157.279 -  }
 157.280 -  
 157.281 -  public Map<String, String> getHeader()
 157.282 -  {
 157.283 -    return this.header;
 157.284 -  }
 157.285 -  
 157.286 -  public Date getDate()
 157.287 -  {
 157.288 -    try
 157.289 -    {
 157.290 -      String date = this.header.get("Date");
 157.291 -      return new Date(Date.parse(date));
 157.292 -    }
 157.293 -    catch(Exception e)
 157.294 -    {
 157.295 -      e.printStackTrace(Debug.getInstance().getStream());
 157.296 -      return null;
 157.297 -    }
 157.298 -  }
 157.299 -
 157.300 -  public void setDate(Date date)
 157.301 -  {
 157.302 -    this.header.put("Date", date.toString());
 157.303 -  }
 157.304 -  
 157.305 -  @Override
 157.306 -  public String toString()
 157.307 -  {
 157.308 -    return getMessageID();
 157.309 -  }
 157.310 -}
   158.1 --- a/trunk/com/so/news/storage/Database.java	Tue Jan 20 10:21:03 2009 +0100
   158.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   158.3 @@ -1,327 +0,0 @@
   158.4 -/*
   158.5 - *   StarOffice News Server
   158.6 - *   see AUTHORS for the list of contributors
   158.7 - *
   158.8 - *   This program is free software: you can redistribute it and/or modify
   158.9 - *   it under the terms of the GNU General Public License as published by
  158.10 - *   the Free Software Foundation, either version 3 of the License, or
  158.11 - *   (at your option) any later version.
  158.12 - *
  158.13 - *   This program is distributed in the hope that it will be useful,
  158.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  158.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  158.16 - *   GNU General Public License for more details.
  158.17 - *
  158.18 - *   You should have received a copy of the GNU General Public License
  158.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  158.20 - */
  158.21 -
  158.22 -package com.so.news.storage;
  158.23 -
  158.24 -import java.sql.Connection;
  158.25 -import java.sql.DriverManager;
  158.26 -import java.sql.ResultSet;
  158.27 -import java.sql.SQLException;
  158.28 -import java.sql.Statement;
  158.29 -
  158.30 -import java.util.zip.CRC32;
  158.31 -import com.so.news.Config;
  158.32 -import com.so.news.util.StringTemplate;
  158.33 -
  158.34 -/**
  158.35 - * Database abstraction class.
  158.36 - * @author Christian Lins (christian.lins@web.de)
  158.37 - */
  158.38 -public class Database
  158.39 -{
  158.40 -  private static Database instance = null;
  158.41 -  
  158.42 -  /**
  158.43 -   * Initializes the Database subsystem, e.g. loading a JDBC driver and
  158.44 -   * connection to the Database Managment System.
  158.45 -   * This method is called when the daemon starts up or at the first
  158.46 -   * call to Database.getInstance().
  158.47 -   * @throws java.lang.Exception
  158.48 -   */
  158.49 -  public static void arise()
  158.50 -    throws Exception
  158.51 -  {
  158.52 -    // Tries to load the Database driver and establish a connection.
  158.53 -    if(instance == null)
  158.54 -      instance = new Database();
  158.55 -  }
  158.56 -  
  158.57 -  /**
  158.58 -   * @return Instance of the current Database backend. Returns null if an error
  158.59 -   * has occurred.
  158.60 -   */
  158.61 -  public static Database getInstance()
  158.62 -  {
  158.63 -    try
  158.64 -    {
  158.65 -      arise();
  158.66 -      return instance;
  158.67 -    }
  158.68 -    catch(Exception ex)
  158.69 -    {
  158.70 -      ex.printStackTrace();
  158.71 -      return null;
  158.72 -    }
  158.73 -  }
  158.74 -  
  158.75 -  private Connection conn = null;
  158.76 -  
  158.77 -  /**
  158.78 -   * Private constructor.
  158.79 -   * @throws java.lang.Exception
  158.80 -   */
  158.81 -  private Database()
  158.82 -    throws Exception
  158.83 -  {
  158.84 -    Class.forName(
  158.85 -            Config.getInstance().get("n3tpd.storage.dbmsdriver", ""));
  158.86 -    this.conn = DriverManager.getConnection(
  158.87 -            Config.getInstance().get("n3tpd.storage.database", ""),
  158.88 -            Config.getInstance().get("n3tpd.storage.user", "n3tpd_user"),
  158.89 -            Config.getInstance().get("n3tpd.storage.password", ""));
  158.90 -    this.conn.setAutoCommit(false);
  158.91 -  }
  158.92 -  
  158.93 -  /**
  158.94 -   * Adds an article to the database.
  158.95 -   * @param article
  158.96 -   * @return
  158.97 -   * @throws java.sql.SQLException
  158.98 -   */
  158.99 -  public boolean addArticle(Article article)
 158.100 -    throws SQLException
 158.101 -  {
 158.102 -    Statement stmt = this.conn.createStatement();
 158.103 -
 158.104 -    String sql0 = "START TRANSACTION";
 158.105 -    String sql1 = "INSERT INTO articles (message_id,header,body)" +
 158.106 -            "VALUES('%mid', '%header', '%body')";
 158.107 -    StringTemplate tmpl = new StringTemplate(sql1);
 158.108 -    tmpl.set("body", article.getBody());
 158.109 -    tmpl.set("mid", article.getMessageID());
 158.110 -    tmpl.set("header", article.getHeaderSource());
 158.111 -    sql1 = tmpl.toString();
 158.112 -    
 158.113 -    String sql2 = "COMMIT";
 158.114 -    
 158.115 -    // Add statements as batch
 158.116 -    stmt.addBatch(sql0);
 158.117 -    stmt.addBatch(sql1);
 158.118 -    
 158.119 -    // TODO: For each newsgroup add a reference
 158.120 -    String sql = "INSERT INTO postings (group_id, article_id, article_index)" +
 158.121 -                 "VALUES (%gid, (SELECT article_id FROM articles WHERE message_id = '%mid')," +
 158.122 -                 " %idx)";
 158.123 -    
 158.124 -    tmpl = new StringTemplate(sql);
 158.125 -    tmpl.set("gid", article.getGroupID());
 158.126 -    tmpl.set("mid", article.getMessageID());
 158.127 -    tmpl.set("idx", getMaxArticleIndex() + 1);
 158.128 -    stmt.addBatch(tmpl.toString());
 158.129 -    
 158.130 -    // Commit
 158.131 -    stmt.addBatch(sql2);
 158.132 -    
 158.133 -    // And execute the batch
 158.134 -    stmt.executeBatch();
 158.135 -    
 158.136 -    return true;
 158.137 -  }
 158.138 -  
 158.139 -  /**
 158.140 -   * Adds a group to the Database.
 158.141 -   * @param name
 158.142 -   * @throws java.sql.SQLException
 158.143 -   */
 158.144 -  public boolean addGroup(String name)
 158.145 -    throws SQLException
 158.146 -  {
 158.147 -    CRC32 crc = new CRC32();
 158.148 -    crc.update(name.getBytes());
 158.149 -    
 158.150 -    long id = crc.getValue();
 158.151 -    
 158.152 -    Statement stmt = conn.createStatement();
 158.153 -    return 1 == stmt.executeUpdate("INSERT INTO Groups (ID, Name) VALUES (" + id + ", '" + name + "')");
 158.154 -  }
 158.155 -  
 158.156 -  public void delete(Article article)
 158.157 -  {
 158.158 -    
 158.159 -  }
 158.160 -  
 158.161 -  public void delete(Group group)
 158.162 -  {
 158.163 -    
 158.164 -  }
 158.165 -  
 158.166 -  public Article getArticle(String messageID)
 158.167 -    throws SQLException
 158.168 -  {
 158.169 -    Statement stmt = this.conn.createStatement();
 158.170 -    ResultSet rs =
 158.171 -      stmt.executeQuery("SELECT * FROM articles WHERE message_id = '" + messageID + "'");
 158.172 -    
 158.173 -    return new Article(rs);
 158.174 -  }
 158.175 -  
 158.176 -  public Article getArticle(long gid, long article_id)
 158.177 -    throws SQLException
 158.178 -  {
 158.179 -    Statement stmt = this.conn.createStatement();
 158.180 -    String sql = "SELECT * FROM articles WHERE article_id = " +
 158.181 -            "(SELECT article_id FROM postings WHERE " +
 158.182 -            "group_id = " + gid + " AND article_id = " + article_id +")";
 158.183 -    ResultSet rs =
 158.184 -      stmt.executeQuery(sql);
 158.185 -    
 158.186 -    if(rs.next())
 158.187 -      return new Article(rs);
 158.188 -    else
 158.189 -      return null;
 158.190 -  }
 158.191 -  
 158.192 -  public ResultSet getArticles()
 158.193 -    throws SQLException
 158.194 -  {
 158.195 -    Statement stmt = conn.createStatement();
 158.196 -    return stmt.executeQuery("SELECT * FROM articles");
 158.197 -  }
 158.198 -  
 158.199 -  /**
 158.200 -   * Reads all Groups from the Database.
 158.201 -   * @return
 158.202 -   * @throws java.sql.SQLException
 158.203 -   */
 158.204 -  public ResultSet getGroups()
 158.205 -    throws SQLException
 158.206 -  {
 158.207 -    Statement stmt = conn.createStatement();
 158.208 -    ResultSet rs = stmt.executeQuery("SELECT * FROM groups");
 158.209 -    
 158.210 -    return rs;
 158.211 -  }
 158.212 -  
 158.213 -  /**
 158.214 -   * Returns the Group that is identified by the name.
 158.215 -   * @param name
 158.216 -   * @return
 158.217 -   * @throws java.sql.SQLException
 158.218 -   */
 158.219 -  public Group getGroup(String name)
 158.220 -    throws SQLException
 158.221 -  {   
 158.222 -    Statement stmt = this.conn.createStatement();
 158.223 -    String sql = "SELECT group_id FROM groups WHERE Name = '%name'";
 158.224 -    StringTemplate tmpl = new StringTemplate(sql);
 158.225 -    tmpl.set("name", name);
 158.226 -    
 158.227 -    ResultSet rs = stmt.executeQuery(tmpl.toString());
 158.228 -  
 158.229 -    if(!rs.next())
 158.230 -      return null;
 158.231 -    else
 158.232 -    {
 158.233 -      long id = rs.getLong("group_id");
 158.234 -      return new Group(name, id);
 158.235 -    }
 158.236 -  }
 158.237 -  
 158.238 -  public int getMaxArticleIndex()
 158.239 -    throws SQLException
 158.240 -  {
 158.241 -    Statement stmt = conn.createStatement();
 158.242 -    ResultSet rs = stmt.executeQuery(
 158.243 -      "SELECT Max(article_index) FROM postings");
 158.244 -    
 158.245 -    if(!rs.next())
 158.246 -      return 0;
 158.247 -    else
 158.248 -      return rs.getInt(1);
 158.249 -  }
 158.250 -  
 158.251 -  public int getLastArticleNumber(Group group)
 158.252 -    throws SQLException
 158.253 -  {
 158.254 -    Statement stmt = conn.createStatement();
 158.255 -    ResultSet rs = stmt.executeQuery(
 158.256 -      "SELECT Max(article_index) FROM postings WHERE group_id = " + group.getID());
 158.257 -    
 158.258 -    if(!rs.next())
 158.259 -      return 0;
 158.260 -    else
 158.261 -      return rs.getInt(1);
 158.262 -  }
 158.263 -  
 158.264 -  public int getFirstArticleNumber(Group group)
 158.265 -    throws SQLException
 158.266 -  {
 158.267 -    Statement stmt = conn.createStatement();
 158.268 -    ResultSet rs = stmt.executeQuery(
 158.269 -      "SELECT Min(article_index) FROM postings WHERE group_id = " + group.getID());
 158.270 -  
 158.271 -    if(!rs.next())
 158.272 -      return 0;
 158.273 -    else
 158.274 -      return rs.getInt(1);
 158.275 -  }
 158.276 -  
 158.277 -  /**
 158.278 -   * Returns a group name identified by the given id.
 158.279 -   * @param id
 158.280 -   * @return
 158.281 -   * @throws java.sql.SQLException
 158.282 -   */
 158.283 -  public String getGroup(int id)
 158.284 -    throws SQLException
 158.285 -  {
 158.286 -    Statement stmt = conn.createStatement();
 158.287 -    ResultSet rs   = stmt.executeQuery(
 158.288 -            "SELECT name FROM groups WHERE group_id = '" + id + "'");
 158.289 -    
 158.290 -    if(rs.next())
 158.291 -    {
 158.292 -      return rs.getString(1);
 158.293 -    }
 158.294 -    else
 158.295 -      return null;
 158.296 -  }
 158.297 -  
 158.298 -  public Article getOldestArticle()
 158.299 -    throws SQLException
 158.300 -  {
 158.301 -    Statement stmt = conn.createStatement();
 158.302 -    ResultSet rs = 
 158.303 -      stmt.executeQuery("SELECT * FROM Articles WHERE Date = (SELECT Min(Date) FROM Articles)");
 158.304 -    
 158.305 -    if(rs.next())
 158.306 -      return new Article(rs);
 158.307 -    else
 158.308 -      return null;
 158.309 -  }
 158.310 -  
 158.311 -  /**
 158.312 -   * Checks if there is a group with the given name in the Database.
 158.313 -   * @param name
 158.314 -   * @return
 158.315 -   * @throws java.sql.SQLException
 158.316 -   */
 158.317 -  public boolean isGroupExisting(String name)
 158.318 -    throws SQLException
 158.319 -  {
 158.320 -    Statement stmt = this.conn.createStatement();
 158.321 -    ResultSet rs   = stmt.executeQuery("SELECT * FROM Groups WHERE Name = '" + name + "'");
 158.322 -    
 158.323 -    return rs.next();
 158.324 -  }
 158.325 -  
 158.326 -  public void updateArticle(Article article)
 158.327 -  {
 158.328 -    
 158.329 -  }
 158.330 -}
   159.1 --- a/trunk/com/so/news/storage/Group.java	Tue Jan 20 10:21:03 2009 +0100
   159.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   159.3 @@ -1,142 +0,0 @@
   159.4 -/*
   159.5 - *   StarOffice News Server
   159.6 - *   see AUTHORS for the list of contributors
   159.7 - *
   159.8 - *   This program is free software: you can redistribute it and/or modify
   159.9 - *   it under the terms of the GNU General Public License as published by
  159.10 - *   the Free Software Foundation, either version 3 of the License, or
  159.11 - *   (at your option) any later version.
  159.12 - *
  159.13 - *   This program is distributed in the hope that it will be useful,
  159.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  159.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  159.16 - *   GNU General Public License for more details.
  159.17 - *
  159.18 - *   You should have received a copy of the GNU General Public License
  159.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  159.20 - */
  159.21 -
  159.22 -package com.so.news.storage;
  159.23 -
  159.24 -import java.sql.ResultSet;
  159.25 -import java.sql.SQLException;
  159.26 -import java.util.ArrayList;
  159.27 -import java.util.List;
  159.28 -import com.so.news.Debug;
  159.29 -
  159.30 -/**
  159.31 - * Represents a logical Group within this newsserver.
  159.32 - * @author Christian Lins
  159.33 - */
  159.34 -public class Group
  159.35 -{
  159.36 -  private long   id;
  159.37 -  private String name;
  159.38 -
  159.39 -  /**
  159.40 -   * Private constructor.
  159.41 -   * @param name
  159.42 -   * @param id
  159.43 -   */
  159.44 -  Group(String name, long id)
  159.45 -  {
  159.46 -    this.id   = id;
  159.47 -    this.name = name;
  159.48 -  }
  159.49 -  
  159.50 -  /**
  159.51 -   * Returns a Group identified by its full name.
  159.52 -   * @param name
  159.53 -   * @return
  159.54 -   */
  159.55 -  public static Group getByName(String name)
  159.56 -  {
  159.57 -    try
  159.58 -    {
  159.59 -      return Database.getInstance().getGroup(name);
  159.60 -    }
  159.61 -    catch(SQLException ex)
  159.62 -    {
  159.63 -      System.err.println(ex.getLocalizedMessage());
  159.64 -      ex.printStackTrace(Debug.getInstance().getStream());
  159.65 -      return null;
  159.66 -    }
  159.67 -  }
  159.68 -
  159.69 -  /**
  159.70 -   * Returns a list of all groups this server handles.
  159.71 -   * @return
  159.72 -   */
  159.73 -  public static ArrayList<Group> getAll()
  159.74 -  {
  159.75 -    ArrayList<Group> buffer = new ArrayList<Group>();
  159.76 -    
  159.77 -    try
  159.78 -    {
  159.79 -      ResultSet rs = Database.getInstance().getGroups();
  159.80 -      
  159.81 -      while(rs.next())
  159.82 -      {
  159.83 -        String name = rs.getString("name");
  159.84 -        long   id   = rs.getLong("group_id");
  159.85 -        
  159.86 -        Group group = new Group(name, id);
  159.87 -        buffer.add(group);
  159.88 -      }
  159.89 -    }
  159.90 -    catch(SQLException ex)
  159.91 -    {
  159.92 -      ex.printStackTrace(Debug.getInstance().getStream());
  159.93 -      System.err.println(ex.getLocalizedMessage());
  159.94 -    }
  159.95 -    
  159.96 -    return buffer;
  159.97 -  }
  159.98 -
  159.99 -  public List<Article> getAllArticles()
 159.100 -    throws SQLException
 159.101 -  {
 159.102 -    return getAllArticles(getFirstArticle(), getLastArticle());
 159.103 -  }
 159.104 -
 159.105 -  public List<Article> getAllArticles(int first, int last)
 159.106 -  {
 159.107 -    return null;
 159.108 -  }
 159.109 -
 159.110 -  public int getFirstArticle()
 159.111 -    throws SQLException
 159.112 -  {
 159.113 -    return Database.getInstance().getFirstArticleNumber(this);
 159.114 -  }
 159.115 -
 159.116 -  public long getID()
 159.117 -  {
 159.118 -    return id;
 159.119 -  }
 159.120 -
 159.121 -  public int getLastArticle()
 159.122 -    throws SQLException
 159.123 -  {
 159.124 -    return Database.getInstance().getLastArticleNumber(this);
 159.125 -  }
 159.126 -
 159.127 -  public String getName()
 159.128 -  {
 159.129 -    return name;
 159.130 -  }
 159.131 -
 159.132 -  public void setName(String name)
 159.133 -  {
 159.134 -    this.name = name;
 159.135 -  }
 159.136 -
 159.137 -  public int getEstimatedArticleCount()
 159.138 -    throws SQLException
 159.139 -  {
 159.140 -    if (getLastArticle() < getFirstArticle())
 159.141 -      return 0;
 159.142 -    return getLastArticle() - getFirstArticle() + 1;
 159.143 -  }
 159.144 -
 159.145 -}
   160.1 --- a/trunk/com/so/news/storage/Purger.java	Tue Jan 20 10:21:03 2009 +0100
   160.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   160.3 @@ -1,96 +0,0 @@
   160.4 -/*
   160.5 - *   StarOffice News Server
   160.6 - *   see AUTHORS for the list of contributors
   160.7 - *
   160.8 - *   This program is free software: you can redistribute it and/or modify
   160.9 - *   it under the terms of the GNU General Public License as published by
  160.10 - *   the Free Software Foundation, either version 3 of the License, or
  160.11 - *   (at your option) any later version.
  160.12 - *
  160.13 - *   This program is distributed in the hope that it will be useful,
  160.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  160.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  160.16 - *   GNU General Public License for more details.
  160.17 - *
  160.18 - *   You should have received a copy of the GNU General Public License
  160.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  160.20 - */
  160.21 -
  160.22 -package com.so.news.storage;
  160.23 -
  160.24 -import java.util.Date;
  160.25 -
  160.26 -import com.so.news.Config;
  160.27 -import com.so.news.Debug;
  160.28 -
  160.29 -/**
  160.30 - * The purger is started in configurable intervals to search
  160.31 - * for old messages that can be purged.
  160.32 - * @author Christian Lins
  160.33 - */
  160.34 -public class Purger extends Thread
  160.35 -{
  160.36 -  private int interval;
  160.37 -  
  160.38 -  public Purger()
  160.39 -  {
  160.40 -    setDaemon(true); // Daemons run only along with the main thread
  160.41 -    setPriority(Thread.MIN_PRIORITY);
  160.42 -
  160.43 -    this.interval = Config.getInstance().get("n3tpd.article.lifetime", 30) * 24 * 60 * 60 * 1000; // Milliseconds
  160.44 -    if(this.interval < 0)
  160.45 -      this.interval = Integer.MAX_VALUE;
  160.46 -  }
  160.47 -  
  160.48 -  /**
  160.49 -   * Runloop of this Purger class.
  160.50 -   */
  160.51 -  @Override
  160.52 -  public void run()
  160.53 -  {
  160.54 -    for(;;)
  160.55 -    {
  160.56 -      purge();
  160.57 -
  160.58 -      try
  160.59 -      {
  160.60 -        sleep(interval);
  160.61 -      }
  160.62 -      catch(InterruptedException e)
  160.63 -      {
  160.64 -        e.printStackTrace(Debug.getInstance().getStream());
  160.65 -      }
  160.66 -    }
  160.67 -  }
  160.68 -
  160.69 -  /**
  160.70 -   * Loops through all messages and deletes them if their time
  160.71 -   * has come.
  160.72 -   */
  160.73 -  private void purge()
  160.74 -  {
  160.75 -    Debug.getInstance().log("Purging old messages...");
  160.76 -
  160.77 -    try
  160.78 -    {
  160.79 -      for(;;)
  160.80 -      {
  160.81 -        Article art = null; //Database.getInstance().getOldestArticle();
  160.82 -        if(art == null) // No articles in the database
  160.83 -          break;
  160.84 -        
  160.85 -        if(art.getDate().getTime() < (new Date().getTime() + this.interval))
  160.86 -        {
  160.87 -          Database.getInstance().delete(art);
  160.88 -          Debug.getInstance().log("Deleted: " + art);
  160.89 -        }
  160.90 -        else
  160.91 -          break;
  160.92 -      }
  160.93 -    }
  160.94 -    catch(Exception ex)
  160.95 -    {
  160.96 -      ex.printStackTrace();
  160.97 -    }
  160.98 -  }
  160.99 -}
   161.1 --- a/trunk/com/so/news/util/StringTemplate.java	Tue Jan 20 10:21:03 2009 +0100
   161.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   161.3 @@ -1,77 +0,0 @@
   161.4 -/*
   161.5 - *   StarOffice News Server
   161.6 - *   see AUTHORS for the list of contributors
   161.7 - *
   161.8 - *   This program is free software: you can redistribute it and/or modify
   161.9 - *   it under the terms of the GNU General Public License as published by
  161.10 - *   the Free Software Foundation, either version 3 of the License, or
  161.11 - *   (at your option) any later version.
  161.12 - *
  161.13 - *   This program is distributed in the hope that it will be useful,
  161.14 - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  161.15 - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  161.16 - *   GNU General Public License for more details.
  161.17 - *
  161.18 - *   You should have received a copy of the GNU General Public License
  161.19 - *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  161.20 - */
  161.21 -
  161.22 -package com.so.news.util;
  161.23 -
  161.24 -import java.util.HashMap;
  161.25 -
  161.26 -/**
  161.27 - * Class that allows simple String template handling.
  161.28 - * @author Christian Lins (christian.lins@web.de)
  161.29 - */
  161.30 -public class StringTemplate 
  161.31 -{
  161.32 -  private String                  str               = null;
  161.33 -  private String                  templateDelimiter = "%";
  161.34 -  private HashMap<String, String> templateValues    = new HashMap<String, String>();
  161.35 -  
  161.36 -  public StringTemplate(String str, String templateDelimiter)
  161.37 -  {
  161.38 -    this.str               = str;
  161.39 -    this.templateDelimiter = templateDelimiter;
  161.40 -  }
  161.41 -  
  161.42 -  public StringTemplate(String str)
  161.43 -  {
  161.44 -    this(str, "%");
  161.45 -  }
  161.46 -  
  161.47 -  public void set(String template, String value)
  161.48 -  {
  161.49 -    this.templateValues.put(template, value);
  161.50 -  }
  161.51 -  
  161.52 -  public void set(String template, long value)
  161.53 -  {
  161.54 -    set(template, Long.toString(value));
  161.55 -  }
  161.56 -  
  161.57 -  public void set(String template, double value)
  161.58 -  {
  161.59 -    set(template, Double.toString(value));
  161.60 -  }
  161.61 -  
  161.62 -  public void set(String template, Object obj)
  161.63 -  {
  161.64 -    set(template, obj.toString());
  161.65 -  }
  161.66 -  
  161.67 -  @Override
  161.68 -  public String toString()
  161.69 -  {
  161.70 -    String ret = new String(str);
  161.71 -    
  161.72 -    for(String key : this.templateValues.keySet())
  161.73 -    {
  161.74 -      String value = this.templateValues.get(key);
  161.75 -      ret = ret.replace(templateDelimiter + key, value);
  161.76 -    }
  161.77 -    
  161.78 -    return ret;
  161.79 -  }
  161.80 -}
   162.1 --- a/trunk/helpers/tbl_mysql6_tmpl.sql	Tue Jan 20 10:21:03 2009 +0100
   162.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   162.3 @@ -1,39 +0,0 @@
   162.4 -CREATE DATABASE staroffice_news;
   162.5 -
   162.6 -CREATE TABLE groups 
   162.7 -(
   162.8 -  group_id      SERIAL,
   162.9 -  name          VARCHAR(80) NOT NULL,
  162.10 -  flags         INTEGER DEFAULT 0 NOT NULL
  162.11 -);
  162.12 -
  162.13 -CREATE UNIQUE INDEX name_id_index ON groups (name);
  162.14 -
  162.15 -CREATE TABLE articles 
  162.16 -(
  162.17 -  article_id    SERIAL,
  162.18 -  message_id    TEXT,
  162.19 -  header        TEXT,
  162.20 -  body          TEXT
  162.21 -);
  162.22 -
  162.23 -CREATE UNIQUE INDEX article_message_index ON articles (message_id(255));
  162.24 -
  162.25 -CREATE TABLE postings 
  162.26 -(
  162.27 -  group_id      INTEGER,
  162.28 -  article_id    INTEGER,
  162.29 -  article_index INTEGER NOT NULL
  162.30 -);
  162.31 -
  162.32 -CREATE UNIQUE INDEX posting_article_index ON postings (article_id);
  162.33 -
  162.34 -CREATE TABLE subscriptions 
  162.35 -(
  162.36 -  group_id    INTEGER
  162.37 -);
  162.38 -    
  162.39 -CREATE TABLE overview 
  162.40 -(
  162.41 -  header      TEXT
  162.42 -);
   163.1 --- a/trunk/rfc3977.txt	Tue Jan 20 10:21:03 2009 +0100
   163.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   163.3 @@ -1,6998 +0,0 @@
   163.4 -
   163.5 -Network Working Group                                         C. Feather
   163.6 -Request for Comments: 3977                                      THUS plc
   163.7 -Obsoletes: 977                                              October 2006
   163.8 -Updates: 2980
   163.9 -Category: Standards Track
  163.10 -
  163.11 -
  163.12 -                 Network News Transfer Protocol (NNTP)
  163.13 -
  163.14 -Status of This Memo
  163.15 -
  163.16 -   This document specifies an Internet standards track protocol for the
  163.17 -   Internet community, and requests discussion and suggestions for
  163.18 -   improvements.  Please refer to the current edition of the "Internet
  163.19 -   Official Protocol Standards" (STD 1) for the standardization state
  163.20 -   and status of this protocol.  Distribution of this memo is unlimited.
  163.21 -
  163.22 -Copyright Notice
  163.23 -
  163.24 -   Copyright (C) The Internet Society (2006).
  163.25 -
  163.26 -Abstract
  163.27 -
  163.28 -   The Network News Transfer Protocol (NNTP) has been in use in the
  163.29 -   Internet for a decade, and remains one of the most popular protocols
  163.30 -   (by volume) in use today.  This document is a replacement for
  163.31 -   RFC 977, and officially updates the protocol specification.  It
  163.32 -   clarifies some vagueness in RFC 977, includes some new base
  163.33 -   functionality, and provides a specific mechanism to add standardized
  163.34 -   extensions to NNTP.
  163.35 -
  163.36 -Table of Contents
  163.37 -
  163.38 -   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .  3
  163.39 -     1.1.  Author's Note . . . . . . . . . . . . . . . . . . . . . .  4
  163.40 -   2.  Notation  . . . . . . . . . . . . . . . . . . . . . . . . . .  5
  163.41 -   3.  Basic Concepts  . . . . . . . . . . . . . . . . . . . . . . .  6
  163.42 -     3.1.  Commands and Responses  . . . . . . . . . . . . . . . . .  6
  163.43 -       3.1.1.  Multi-line Data Blocks . . . . . . . . . . . . . . . . 8
  163.44 -     3.2.  Response Codes  . . . . . . . . . . . . . . . . . . . . .  9
  163.45 -       3.2.1.  Generic Response Codes  . . . . . . . . . . . . . . . 10
  163.46 -         3.2.1.1.  Examples  . . . . . . . . . . . . . . . . . . . . 12
  163.47 -     3.3.  Capabilities and Extensions . . . . . . . . . . . . . . . 14
  163.48 -       3.3.1.  Capability Descriptions . . . . . . . . . . . . . . . 14
  163.49 -       3.3.2.  Standard Capabilities . . . . . . . . . . . . . . . . 15
  163.50 -       3.3.3.  Extensions  . . . . . . . . . . . . . . . . . . . . . 16
  163.51 -       3.3.4.  Initial IANA Register . . . . . . . . . . . . . . . . 18
  163.52 -     3.4.  Mandatory and Optional Commands . . . . . . . . . . . . . 20
  163.53 -
  163.54 -
  163.55 -
  163.56 -Feather                     Standards Track                     [Page 1]
  163.57 -
  163.58 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
  163.59 -
  163.60 -
  163.61 -       3.4.1.  Reading and Transit Servers . . . . . . . . . . . . . 21
  163.62 -       3.4.2.  Mode Switching  . . . . . . . . . . . . . . . . . . . 21
  163.63 -     3.5.  Pipelining  . . . . . . . . . . . . . . . . . . . . . . . 22
  163.64 -       3.5.1.  Examples  . . . . . . . . . . . . . . . . . . . . . . 23
  163.65 -     3.6.  Articles  . . . . . . . . . . . . . . . . . . . . . . . . 24
  163.66 -   4.  The WILDMAT Format  . . . . . . . . . . . . . . . . . . . . . 25
  163.67 -     4.1.  Wildmat Syntax  . . . . . . . . . . . . . . . . . . . . . 26
  163.68 -     4.2.  Wildmat Semantics . . . . . . . . . . . . . . . . . . . . 26
  163.69 -     4.3.  Extensions  . . . . . . . . . . . . . . . . . . . . . . . 27
  163.70 -     4.4.  Examples  . . . . . . . . . . . . . . . . . . . . . . . . 27
  163.71 -   5.  Session Administration Commands . . . . . . . . . . . . . . . 28
  163.72 -     5.1.  Initial Connection  . . . . . . . . . . . . . . . . . . . 28
  163.73 -     5.2.  CAPABILITIES  . . . . . . . . . . . . . . . . . . . . . . 29
  163.74 -     5.3.  MODE READER . . . . . . . . . . . . . . . . . . . . . . . 32
  163.75 -     5.4.  QUIT  . . . . . . . . . . . . . . . . . . . . . . . . . . 34
  163.76 -   6.  Article Posting and Retrieval . . . . . . . . . . . . . . . . 35
  163.77 -     6.1.  Group and Article Selection . . . . . . . . . . . . . . . 36
  163.78 -       6.1.1.  GROUP . . . . . . . . . . . . . . . . . . . . . . . . 36
  163.79 -       6.1.2.  LISTGROUP . . . . . . . . . . . . . . . . . . . . . . 39
  163.80 -       6.1.3.  LAST  . . . . . . . . . . . . . . . . . . . . . . . . 42
  163.81 -       6.1.4.  NEXT  . . . . . . . . . . . . . . . . . . . . . . . . 44
  163.82 -     6.2.  Retrieval of Articles and Article Sections  . . . . . . . 45
  163.83 -       6.2.1.  ARTICLE . . . . . . . . . . . . . . . . . . . . . . . 46
  163.84 -       6.2.2.  HEAD  . . . . . . . . . . . . . . . . . . . . . . . . 49
  163.85 -       6.2.3.  BODY  . . . . . . . . . . . . . . . . . . . . . . . . 51
  163.86 -       6.2.4.  STAT  . . . . . . . . . . . . . . . . . . . . . . . . 53
  163.87 -     6.3.  Article Posting . . . . . . . . . . . . . . . . . . . . . 56
  163.88 -       6.3.1.  POST  . . . . . . . . . . . . . . . . . . . . . . . . 56
  163.89 -       6.3.2.  IHAVE . . . . . . . . . . . . . . . . . . . . . . . . 58
  163.90 -   7.  Information Commands  . . . . . . . . . . . . . . . . . . . . 61
  163.91 -     7.1.  DATE  . . . . . . . . . . . . . . . . . . . . . . . . . . 61
  163.92 -     7.2.  HELP  . . . . . . . . . . . . . . . . . . . . . . . . . . 62
  163.93 -     7.3.  NEWGROUPS . . . . . . . . . . . . . . . . . . . . . . . . 63
  163.94 -     7.4.  NEWNEWS . . . . . . . . . . . . . . . . . . . . . . . . . 64
  163.95 -     7.5.  Time  . . . . . . . . . . . . . . . . . . . . . . . . . . 65
  163.96 -       7.5.1.  Examples  . . . . . . . . . . . . . . . . . . . . . . 66
  163.97 -     7.6.  The LIST Commands . . . . . . . . . . . . . . . . . . . . 66
  163.98 -       7.6.1.  LIST  . . . . . . . . . . . . . . . . . . . . . . . . 67
  163.99 -       7.6.2.  Standard LIST Keywords  . . . . . . . . . . . . . . . 69
 163.100 -       7.6.3.  LIST ACTIVE . . . . . . . . . . . . . . . . . . . . . 70
 163.101 -       7.6.4.  LIST ACTIVE.TIMES . . . . . . . . . . . . . . . . . . 71
 163.102 -       7.6.5.  LIST DISTRIB.PATS . . . . . . . . . . . . . . . . . . 72
 163.103 -       7.6.6.  LIST NEWSGROUPS . . . . . . . . . . . . . . . . . . . 73
 163.104 -   8.  Article Field Access Commands . . . . . . . . . . . . . . . . 73
 163.105 -     8.1.  Article Metadata  . . . . . . . . . . . . . . . . . . . . 74
 163.106 -       8.1.1.  The :bytes Metadata Item  . . . . . . . . . . . . . . 74
 163.107 -       8.1.2.  The :lines Metadata Item  . . . . . . . . . . . . . . 75
 163.108 -     8.2.  Database Consistency  . . . . . . . . . . . . . . . . . . 75
 163.109 -
 163.110 -
 163.111 -
 163.112 -Feather                     Standards Track                     [Page 2]
 163.113 -
 163.114 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.115 -
 163.116 -
 163.117 -     8.3.  OVER  . . . . . . . . . . . . . . . . . . . . . . . . . . 76
 163.118 -     8.4.  LIST OVERVIEW.FMT . . . . . . . . . . . . . . . . . . . . 81
 163.119 -     8.5.  HDR . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
 163.120 -     8.6.  LIST HEADERS  . . . . . . . . . . . . . . . . . . . . . . 87
 163.121 -   9.  Augmented BNF Syntax for NNTP . . . . . . . . . . . . . . . . 90
 163.122 -     9.1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . 90
 163.123 -     9.2.  Commands  . . . . . . . . . . . . . . . . . . . . . . . . 92
 163.124 -     9.3.  Command Continuation  . . . . . . . . . . . . . . . . . . 93
 163.125 -     9.4.  Responses . . . . . . . . . . . . . . . . . . . . . . . . 93
 163.126 -       9.4.1.  Generic Responses . . . . . . . . . . . . . . . . . . 93
 163.127 -       9.4.2.  Initial Response Line Contents  . . . . . . . . . . . 94
 163.128 -       9.4.3.  Multi-line Response Contents  . . . . . . . . . . . . 94
 163.129 -     9.5.  Capability Lines  . . . . . . . . . . . . . . . . . . . . 95
 163.130 -     9.6.  LIST Variants . . . . . . . . . . . . . . . . . . . . . . 96
 163.131 -     9.7.  Articles  . . . . . . . . . . . . . . . . . . . . . . . . 97
 163.132 -     9.8.  General Non-terminals . . . . . . . . . . . . . . . . . . 97
 163.133 -     9.9.  Extensions and Validation . . . . . . . . . . . . . . . . 99
 163.134 -   10. Internationalisation Considerations . . . . . . . . . . . . .100
 163.135 -     10.1. Introduction and Historical Situation . . . . . . . . . .100
 163.136 -     10.2. This Specification  . . . . . . . . . . . . . . . . . . .101
 163.137 -     10.3. Outstanding Issues  . . . . . . . . . . . . . . . . . . .102
 163.138 -   11. IANA Considerations . . . . . . . . . . . . . . . . . . . . .103
 163.139 -   12. Security Considerations . . . . . . . . . . . . . . . . . . .103
 163.140 -     12.1. Personal and Proprietary Information  . . . . . . . . . .104
 163.141 -     12.2. Abuse of Server Log Information . . . . . . . . . . . . .104
 163.142 -     12.3. Weak Authentication and Access Control  . . . . . . . . .104
 163.143 -     12.4. DNS Spoofing  . . . . . . . . . . . . . . . . . . . . . .104
 163.144 -     12.5. UTF-8 Issues  . . . . . . . . . . . . . . . . . . . . . .105
 163.145 -     12.6. Caching of Capability Lists . . . . . . . . . . . . . . .106
 163.146 -   13. Acknowledgements  . . . . . . . . . . . . . . . . . . . . . .107
 163.147 -   14. References  . . . . . . . . . . . . . . . . . . . . . . . . .110
 163.148 -     14.1. Normative References  . . . . . . . . . . . . . . . . . .110
 163.149 -     14.2. Informative References  . . . . . . . . . . . . . . . . .110
 163.150 -   A.  Interaction with Other Specifications . . . . . . . . . . . .112
 163.151 -     A.1.  Header Folding  . . . . . . . . . . . . . . . . . . . . .112
 163.152 -     A.2.  Message-IDs . . . . . . . . . . . . . . . . . . . . . . .112
 163.153 -     A.3.  Article Posting . . . . . . . . . . . . . . . . . . . . .114
 163.154 -   B.  Summary of Commands . . . . . . . . . . . . . . . . . . . . .115
 163.155 -   C.  Summary of Response Codes . . . . . . . . . . . . . . . . . .117
 163.156 -   D.  Changes from RFC 977  . . . . . . . . . . . . . . . . . . . .121
 163.157 -
 163.158 -1.  Introduction
 163.159 -
 163.160 -   This document specifies the Network News Transfer Protocol (NNTP),
 163.161 -   which is used for the distribution, inquiry, retrieval, and posting
 163.162 -   of Netnews articles using a reliable stream-based mechanism.  For
 163.163 -   news-reading clients, NNTP enables retrieval of news articles that
 163.164 -
 163.165 -
 163.166 -
 163.167 -
 163.168 -Feather                     Standards Track                     [Page 3]
 163.169 -
 163.170 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.171 -
 163.172 -
 163.173 -   are stored in a central database, giving subscribers the ability to
 163.174 -   select only those articles they wish to read.
 163.175 -
 163.176 -   The Netnews model provides for indexing, cross-referencing, and
 163.177 -   expiration of aged messages.  NNTP is designed for efficient
 163.178 -   transmission of Netnews articles over a reliable full duplex
 163.179 -   communication channel.
 163.180 -
 163.181 -   Although the protocol specification in this document is largely
 163.182 -   compatible with the version specified in RFC 977 [RFC977], a number
 163.183 -   of changes are summarised in Appendix D.  In particular:
 163.184 -
 163.185 -   o  the default character set is changed from US-ASCII [ANSI1986] to
 163.186 -      UTF-8 [RFC3629] (note that US-ASCII is a subset of UTF-8);
 163.187 -
 163.188 -   o  a number of commands that were optional in RFC 977 or that have
 163.189 -      been taken from RFC 2980 [RFC2980] are now mandatory; and
 163.190 -
 163.191 -   o  a CAPABILITIES command has been added to allow clients to
 163.192 -      determine what functionality is available from a server.
 163.193 -
 163.194 -   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
 163.195 -   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
 163.196 -   document are to be interpreted as described in RFC 2119 [RFC2119].
 163.197 -
 163.198 -   An implementation is not compliant if it fails to satisfy one or more
 163.199 -   of the MUST requirements for this protocol.  An implementation that
 163.200 -   satisfies all the MUST and all the SHOULD requirements for its
 163.201 -   protocols is said to be "unconditionally compliant"; one that
 163.202 -   satisfies all the MUST requirements but not all the SHOULD
 163.203 -   requirements for NNTP is said to be "conditionally compliant".
 163.204 -
 163.205 -   For the remainder of this document, the terms "client" and "client
 163.206 -   host" refer to a host making use of the NNTP service, while the terms
 163.207 -   "server" and "server host" refer to a host that offers the NNTP
 163.208 -   service.
 163.209 -
 163.210 -1.1.  Author's Note
 163.211 -
 163.212 -   This document is written in XML using an NNTP-specific DTD.  Custom
 163.213 -   software is used to convert this to RFC 2629 [RFC2629] format, and
 163.214 -   then the public "xml2rfc" package to further reduce this to text,
 163.215 -   nroff source, and HTML.
 163.216 -
 163.217 -   No perl was used in producing this document.
 163.218 -
 163.219 -
 163.220 -
 163.221 -
 163.222 -
 163.223 -
 163.224 -Feather                     Standards Track                     [Page 4]
 163.225 -
 163.226 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.227 -
 163.228 -
 163.229 -2.  Notation
 163.230 -
 163.231 -   The following notational conventions are used in this document.
 163.232 -
 163.233 -     UPPERCASE     indicates literal text to be included in the
 163.234 -                   command.
 163.235 -
 163.236 -     lowercase     indicates a token described elsewhere.
 163.237 -
 163.238 -     [brackets]    indicate that the enclosed material is optional.
 163.239 -
 163.240 -     elliptical    indicates that the argument may be repeated any
 163.241 -     ... marks     number of times (it must occur at least once).
 163.242 -
 163.243 -     vertical|bar  indicates a choice of two mutually exclusive
 163.244 -                   arguments (exactly one must be provided).
 163.245 -
 163.246 -   The name "message-id" for a command or response argument indicates
 163.247 -   that it is the message-id of an article as described in Section 3.6,
 163.248 -   including the angle brackets.
 163.249 -
 163.250 -   The name "wildmat" for an argument indicates that it is a wildmat as
 163.251 -   defined in Section 4.  If the argument does not meet the requirements
 163.252 -   of that section (for example, if it does not fit the grammar of
 163.253 -   Section 4.1), the NNTP server MAY place some interpretation on it
 163.254 -   (not specified by this document) or otherwise MUST treat it as a
 163.255 -   syntax error.
 163.256 -
 163.257 -   Responses for each command will be described in tables listing the
 163.258 -   required format of a response followed by the meaning that should be
 163.259 -   ascribed to that response.
 163.260 -
 163.261 -   The terms "NUL", "TAB", "LF", "CR, and "space" refer to the octets
 163.262 -   %x00, %x09, %x0A, %x0D, and %x20, respectively (that is, the octets
 163.263 -   with those codes in US-ASCII [ANSI1986] and thus in UTF-8 [RFC3629]).
 163.264 -   The term "CRLF" or "CRLF pair" means the sequence CR immediately
 163.265 -   followed by LF (that is, %x0D.0A).  A "printable US-ASCII character"
 163.266 -   is an octet in the range %x21-7E.  Quoted characters refer to the
 163.267 -   octets with those codes in US-ASCII (so "." and "<" refer to %x2E and
 163.268 -   %x3C) and will always be printable US-ASCII characters; similarly,
 163.269 -   "digit" refers to the octets %x30-39.
 163.270 -
 163.271 -   A "keyword" MUST consist only of US-ASCII letters, digits, and the
 163.272 -   characters dot (".") and dash ("-") and MUST begin with a letter.
 163.273 -   Keywords MUST be at least three characters in length.
 163.274 -
 163.275 -
 163.276 -
 163.277 -
 163.278 -
 163.279 -
 163.280 -Feather                     Standards Track                     [Page 5]
 163.281 -
 163.282 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.283 -
 163.284 -
 163.285 -   Examples in this document are not normative but serve to illustrate
 163.286 -   usages, arguments, and responses.  In the examples, a "[C]" will be
 163.287 -   used to represent the client host and an "[S]" will be used to
 163.288 -   represent the server host.  Most of the examples do not rely on a
 163.289 -   particular server state.  In some cases, however, they do assume that
 163.290 -   the currently selected newsgroup (see the GROUP command,
 163.291 -   Section 6.1.1) is invalid; when so, this is indicated at the start of
 163.292 -   the example.  Examples may use commands or other keywords not defined
 163.293 -   in this specification (such as an XENCRYPT command).  These will be
 163.294 -   used to illustrate some point and do not imply that any such command
 163.295 -   is defined elsewhere or needs to exist in any particular
 163.296 -   implementation.
 163.297 -
 163.298 -   Terms that might be read as specifying details of a client or server
 163.299 -   implementation, such as "database", are used simply to ease
 163.300 -   description.  Provided that implementations conform to the protocol
 163.301 -   and format specifications in this document, no specific technique is
 163.302 -   mandated.
 163.303 -
 163.304 -3.  Basic Concepts
 163.305 -
 163.306 -3.1.  Commands and Responses
 163.307 -
 163.308 -   NNTP operates over any reliable bi-directional 8-bit-wide data stream
 163.309 -   channel.  When the connection is established, the NNTP server host
 163.310 -   MUST send a greeting.  The client host and server host then exchange
 163.311 -   commands and responses (respectively) until the connection is closed
 163.312 -   or aborted.  If the connection used is TCP, then the server host
 163.313 -   starts the NNTP service by listening on a TCP port.  When a client
 163.314 -   host wishes to make use of the service, it MUST establish a TCP
 163.315 -   connection with the server host by connecting to that host on the
 163.316 -   same port on which the server is listening.
 163.317 -
 163.318 -   The character set for all NNTP commands is UTF-8 [RFC3629].  Commands
 163.319 -   in NNTP MUST consist of a keyword, which MAY be followed by one or
 163.320 -   more arguments.  A CRLF pair MUST terminate all commands.  Multiple
 163.321 -   commands MUST NOT be on the same line.  Unless otherwise noted
 163.322 -   elsewhere in this document, arguments SHOULD consist of printable US-
 163.323 -   ASCII characters.  Keywords and arguments MUST each be separated by
 163.324 -   one or more space or TAB characters.  Command lines MUST NOT exceed
 163.325 -   512 octets, which includes the terminating CRLF pair.  The arguments
 163.326 -   MUST NOT exceed 497 octets.  A server MAY relax these limits for
 163.327 -   commands defined in an extension.
 163.328 -
 163.329 -   Where this specification permits UTF-8 characters outside the range
 163.330 -   of U+0000 to U+007F, implementations MUST NOT use the Byte Order Mark
 163.331 -   (U+FEFF, encoding %xEF.BB.BF) and MUST use the Word Joiner (U+2060,
 163.332 -   encoding %xE2.91.A0) for the meaning Zero Width No-Break Space in
 163.333 -
 163.334 -
 163.335 -
 163.336 -Feather                     Standards Track                     [Page 6]
 163.337 -
 163.338 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.339 -
 163.340 -
 163.341 -   command lines and the initial lines of responses.  Implementations
 163.342 -   SHOULD apply these same principles throughout.
 163.343 -
 163.344 -   The term "character" means a single Unicode code point.
 163.345 -   Implementations are not required to carry out Unicode normalisation.
 163.346 -   Thus, U+0084 (A-dieresis) is one character, while U+0041 U+0308 (A
 163.347 -   composed with dieresis) is two; the two need not be treated as
 163.348 -   equivalent.
 163.349 -
 163.350 -   Commands may have variants; if so, they use a second keyword
 163.351 -   immediately after the first to indicate which variant is required.
 163.352 -   The only such commands in this specification are LIST and MODE.  Note
 163.353 -   that such variants are sometimes referred to as if they were commands
 163.354 -   in their own right: "the LIST ACTIVE" command should be read as
 163.355 -   shorthand for "the ACTIVE variant of the LIST command".
 163.356 -
 163.357 -   Keywords are case insensitive; the case of keywords for commands MUST
 163.358 -   be ignored by the server.  Command and response arguments are case or
 163.359 -   language specific only when stated, either in this document or in
 163.360 -   other relevant specifications.
 163.361 -
 163.362 -   In some cases, a command involves more data than just a single line.
 163.363 -   The further data may be sent either immediately after the command
 163.364 -   line (there are no instances of this in this specification, but there
 163.365 -   are in extensions such as [NNTP-STREAM]) or following a request from
 163.366 -   the server (indicated by a 3xx response).
 163.367 -
 163.368 -   Each response MUST start with a three-digit response code that is
 163.369 -   sufficient to distinguish all responses.  Certain valid responses are
 163.370 -   defined to be multi-line; for all others, the response is contained
 163.371 -   in a single line.  The initial line of the response MUST NOT exceed
 163.372 -   512 octets, which includes the response code and the terminating CRLF
 163.373 -   pair; an extension MAY specify a greater maximum for commands that it
 163.374 -   defines, but not for any other command.  Single-line responses
 163.375 -   consist of an initial line only.  Multi-line responses consist of an
 163.376 -   initial line followed by a multi-line data block.
 163.377 -
 163.378 -   An NNTP server MAY have an inactivity autologout timer.  Such a timer
 163.379 -   SHOULD be of at least three minutes' duration, with the exception
 163.380 -   that there MAY be a shorter limit on how long the server is willing
 163.381 -   to wait for the first command from the client.  The receipt of any
 163.382 -   command from the client during the timer interval SHOULD suffice to
 163.383 -   reset the autologout timer.  Similarly, the receipt of any
 163.384 -   significant amount of data from a client that is sending a multi-line
 163.385 -   data block (such as during a POST or IHAVE command) SHOULD suffice to
 163.386 -   reset the autologout timer.  When the timer expires, the server
 163.387 -   SHOULD close the connection without sending any response to the
 163.388 -   client.
 163.389 -
 163.390 -
 163.391 -
 163.392 -Feather                     Standards Track                     [Page 7]
 163.393 -
 163.394 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.395 -
 163.396 -
 163.397 -3.1.1.  Multi-line Data Blocks
 163.398 -
 163.399 -   A multi-line data block is used in certain commands and responses.
 163.400 -   It MUST adhere to the following rules:
 163.401 -
 163.402 -   1.  The block consists of a sequence of zero or more "lines", each
 163.403 -       being a stream of octets ending with a CRLF pair.  Apart from
 163.404 -       those line endings, the stream MUST NOT include the octets NUL,
 163.405 -       LF, or CR.
 163.406 -
 163.407 -   2.  In a multi-line response, the block immediately follows the CRLF
 163.408 -       at the end of the initial line of the response.  When used in any
 163.409 -       other context, the specific command will define when the block is
 163.410 -       sent.
 163.411 -
 163.412 -   3.  If any line of the data block begins with the "termination octet"
 163.413 -       ("." or %x2E), that line MUST be "dot-stuffed" by prepending an
 163.414 -       additional termination octet to that line of the block.
 163.415 -
 163.416 -   4.  The lines of the block MUST be followed by a terminating line
 163.417 -       consisting of a single termination octet followed by a CRLF pair
 163.418 -       in the normal way.  Thus, unless it is empty, a multi-line block
 163.419 -       is always terminated with the five octets CRLF "." CRLF
 163.420 -       (%x0D.0A.2E.0D.0A).
 163.421 -
 163.422 -   5.  When a multi-line block is interpreted, the "dot-stuffing" MUST
 163.423 -       be undone; i.e., the recipient MUST ensure that, in any line
 163.424 -       beginning with the termination octet followed by octets other
 163.425 -       than a CRLF pair, that initial termination octet is disregarded.
 163.426 -
 163.427 -   6.  Likewise, the terminating line ("." CRLF or %x2E.0D.0A) MUST NOT
 163.428 -       be considered part of the multi-line block; i.e., the recipient
 163.429 -       MUST ensure that any line beginning with the termination octet
 163.430 -       followed immediately by a CRLF pair is disregarded.  (The first
 163.431 -       CRLF pair of the terminating CRLF "." CRLF of a non-empty block
 163.432 -       is, of course, part of the last line of the block.)
 163.433 -
 163.434 -   Note that texts using an encoding (such as UTF-16 or UTF-32) that may
 163.435 -   contain the octets NUL, LF, or CR other than a CRLF pair cannot be
 163.436 -   reliably conveyed in the above format (that is, they violate the MUST
 163.437 -   requirement above).  However, except when stated otherwise, this
 163.438 -   specification does not require the content to be UTF-8, and therefore
 163.439 -   (subject to that same requirement) it MAY include octets above and
 163.440 -   below 128 mixed arbitrarily.
 163.441 -
 163.442 -   This document does not place any limit on the length of a line in a
 163.443 -   multi-line block.  However, the standards that define the format of
 163.444 -   articles may do so.
 163.445 -
 163.446 -
 163.447 -
 163.448 -Feather                     Standards Track                     [Page 8]
 163.449 -
 163.450 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.451 -
 163.452 -
 163.453 -3.2.  Response Codes
 163.454 -
 163.455 -   Each response MUST begin with a three-digit status indicator.  These
 163.456 -   are status reports from the server and indicate the response to the
 163.457 -   last command received from the client.
 163.458 -
 163.459 -   The first digit of the response broadly indicates the success,
 163.460 -   failure, or progress of the previous command:
 163.461 -
 163.462 -      1xx - Informative message
 163.463 -      2xx - Command completed OK
 163.464 -      3xx - Command OK so far; send the rest of it
 163.465 -      4xx - Command was syntactically correct but failed for some reason
 163.466 -      5xx - Command unknown, unsupported, unavailable, or syntax error
 163.467 -
 163.468 -   The next digit in the code indicates the function response category:
 163.469 -
 163.470 -      x0x - Connection, setup, and miscellaneous messages
 163.471 -      x1x - Newsgroup selection
 163.472 -      x2x - Article selection
 163.473 -      x3x - Distribution functions
 163.474 -      x4x - Posting
 163.475 -      x8x - Reserved for authentication and privacy extensions
 163.476 -      x9x - Reserved for private use (non-standard extensions)
 163.477 -
 163.478 -   Certain responses contain arguments such as numbers and names in
 163.479 -   addition to the status indicator.  In those cases, to simplify
 163.480 -   interpretation by the client, the number and type of such arguments
 163.481 -   is fixed for each response code, as is whether the code is
 163.482 -   single-line or multi-line.  Any extension MUST follow this principle
 163.483 -   as well.  Note that, for historical reasons, the 211 response code is
 163.484 -   an exception to this in that the response may be single-line or
 163.485 -   multi-line depending on the command (GROUP or LISTGROUP) that
 163.486 -   generated it.  In all other cases, the client MUST only use the
 163.487 -   status indicator itself to determine the nature of the response.  The
 163.488 -   exact response codes that can be returned by any given command are
 163.489 -   detailed in the description of that command.
 163.490 -
 163.491 -   Arguments MUST be separated from the numeric status indicator and
 163.492 -   from each other by a single space.  All numeric arguments MUST be in
 163.493 -   base 10 (decimal) format and MAY have leading zeros.  String
 163.494 -   arguments MUST contain at least one character and MUST NOT contain
 163.495 -   TAB, LF, CR, or space.  The server MAY add any text after the
 163.496 -   response code or last argument, as appropriate, and the client MUST
 163.497 -   NOT make decisions based on this text.  Such text MUST be separated
 163.498 -   from the numeric status indicator or the last argument by at least
 163.499 -   one space.
 163.500 -
 163.501 -
 163.502 -
 163.503 -
 163.504 -Feather                     Standards Track                     [Page 9]
 163.505 -
 163.506 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.507 -
 163.508 -
 163.509 -   The server MUST respond to any command with the appropriate generic
 163.510 -   response (given in Section 3.2.1) if it represents the situation.
 163.511 -   Otherwise, each recognized command MUST return one of the response
 163.512 -   codes specifically listed in its description or in an extension.  A
 163.513 -   server MAY provide extensions to this specification, including new
 163.514 -   commands, new variants or features of existing commands, and other
 163.515 -   ways of changing the internal state of the server.  However, the
 163.516 -   server MUST NOT produce any other responses to a client that does not
 163.517 -   invoke any of the additional features.  (Therefore, a client that
 163.518 -   restricts itself to this specification will only receive the
 163.519 -   responses that are listed.)
 163.520 -
 163.521 -   If a client receives an unexpected response, it SHOULD use the first
 163.522 -   digit of the response to determine the result.  For example, an
 163.523 -   unexpected 2xx should be taken as success, and an unexpected 4xx or
 163.524 -   5xx as failure.
 163.525 -
 163.526 -   Response codes not specified in this document MAY be used for any
 163.527 -   installation-specific additional commands also not specified.  These
 163.528 -   SHOULD be chosen to fit the pattern of x9x specified above.
 163.529 -
 163.530 -   Neither this document nor any registered extension (see
 163.531 -   Section 3.3.3) will specify any response codes of the x9x pattern.
 163.532 -   (Implementers of extensions are accordingly cautioned not to use such
 163.533 -   responses for extensions that may subsequently be submitted for
 163.534 -   registration.)
 163.535 -
 163.536 -3.2.1.  Generic Response Codes
 163.537 -
 163.538 -   The server MUST respond to any command with the appropriate one of
 163.539 -   the following generic responses if it represents the situation.
 163.540 -
 163.541 -   If the command is not recognized, or if it is an optional command
 163.542 -   that is not implemented by the server, the response code 500 MUST be
 163.543 -   returned.
 163.544 -
 163.545 -   If there is a syntax error in the arguments of a recognized command,
 163.546 -   including the case where more arguments are provided than the command
 163.547 -   specifies or the command line is longer than the server accepts, the
 163.548 -   response code 501 MUST be returned.  The line MUST NOT be truncated
 163.549 -   or split and then interpreted.  Note that where a command has
 163.550 -   variants depending on a second keyword (e.g., LIST ACTIVE and LIST
 163.551 -   NEWSGROUPS), 501 MUST be used when the base command is implemented
 163.552 -   but the requested variant is not, and 500 MUST be used only when the
 163.553 -   base command itself is not implemented.
 163.554 -
 163.555 -   If an argument is required to be a base64-encoded string [RFC4648]
 163.556 -   (there are no such arguments in this specification, but there may be
 163.557 -
 163.558 -
 163.559 -
 163.560 -Feather                     Standards Track                    [Page 10]
 163.561 -
 163.562 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.563 -
 163.564 -
 163.565 -   in extensions) and is not validly encoded, the response code 504 MUST
 163.566 -   be returned.
 163.567 -
 163.568 -   If the server experiences an internal fault or problem that means it
 163.569 -   is unable to carry out the command (for example, a necessary file is
 163.570 -   missing or a necessary service could not be contacted), the response
 163.571 -   code 403 MUST be returned.  If the server recognizes the command but
 163.572 -   does not provide an optional feature (for example, because it does
 163.573 -   not store the required information), or if it only handles a subset
 163.574 -   of legitimate cases (see the HDR command, Section 8.5, for an
 163.575 -   example), the response code 503 MUST be returned.
 163.576 -
 163.577 -   If the client is not authorized to use the specified facility when
 163.578 -   the server is in its current state, then the appropriate one of the
 163.579 -   following response codes MUST be used.
 163.580 -
 163.581 -   502: It is necessary to terminate the connection and to start a new
 163.582 -      one with the appropriate authority before the command can be used.
 163.583 -      Historically, some mode-switching servers (see Section 3.4.1) used
 163.584 -      this response to indicate that this command will become available
 163.585 -      after the MODE READER command (Section 5.3) is used, but this
 163.586 -      usage does not conform to this specification and MUST NOT be used.
 163.587 -      Note that the server MUST NOT close the connection immediately
 163.588 -      after a 502 response except at the initial connection
 163.589 -      (Section 5.1) and with the MODE READER command.
 163.590 -
 163.591 -   480: The client must authenticate itself to the server (that is, it
 163.592 -      must provide information as to the identity of the client) before
 163.593 -      the facility can be used on this connection.  This will involve
 163.594 -      the use of an authentication extension such as [NNTP-AUTH].
 163.595 -
 163.596 -   483: The client must negotiate appropriate privacy protection on the
 163.597 -      connection.  This will involve the use of a privacy extension such
 163.598 -      as [NNTP-TLS].
 163.599 -
 163.600 -   401: The client must change the state of the connection in some other
 163.601 -      manner.  The first argument of the response MUST be the capability
 163.602 -      label (see Section 5.2) of the facility that provides the
 163.603 -      necessary mechanism (usually an extension, which may be a private
 163.604 -      extension).  The server MUST NOT use this response code except as
 163.605 -      specified by the definition of the capability in question.
 163.606 -
 163.607 -   If the server has to terminate the connection for some reason, it
 163.608 -   MUST give a 400 response code to the next command and then
 163.609 -   immediately close the connection.  Following a 400 response, clients
 163.610 -   SHOULD NOT simply reconnect immediately and retry the same actions.
 163.611 -   Rather, a client SHOULD either use an exponentially increasing delay
 163.612 -   between retries (e.g., double the waiting time after each 400
 163.613 -
 163.614 -
 163.615 -
 163.616 -Feather                     Standards Track                    [Page 11]
 163.617 -
 163.618 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.619 -
 163.620 -
 163.621 -   response) or present any associated text to the user for them to
 163.622 -   decide whether and when to retry.
 163.623 -
 163.624 -   The client MUST be prepared to receive any of these responses for any
 163.625 -   command (except, of course, that the server MUST NOT generate a 500
 163.626 -   response code for mandatory commands).
 163.627 -
 163.628 -3.2.1.1.  Examples
 163.629 -
 163.630 -   Example of an unknown command:
 163.631 -
 163.632 -      [C] MAIL
 163.633 -      [S] 500 Unknown command
 163.634 -
 163.635 -   Example of an unsupported command:
 163.636 -
 163.637 -      [C] CAPABILITIES
 163.638 -      [S] 101 Capability list:
 163.639 -      [S] VERSION 2
 163.640 -      [S] READER
 163.641 -      [S] NEWNEWS
 163.642 -      [S] LIST ACTIVE NEWSGROUPS
 163.643 -      [S] .
 163.644 -      [C] OVER
 163.645 -      [S] 500 Unknown command
 163.646 -
 163.647 -   Example of an unsupported variant:
 163.648 -
 163.649 -      [C] MODE POSTER
 163.650 -      [S] 501 Unknown MODE option
 163.651 -
 163.652 -   Example of a syntax error:
 163.653 -
 163.654 -      [C] ARTICLE a.message.id@no.angle.brackets
 163.655 -      [S] 501 Syntax error
 163.656 -
 163.657 -   Example of an overlong command line:
 163.658 -
 163.659 -      [C] HEAD 53 54 55
 163.660 -      [S] 501 Too many arguments
 163.661 -
 163.662 -   Example of a bad wildmat:
 163.663 -
 163.664 -      [C] LIST ACTIVE u[ks].*
 163.665 -      [S] 501 Syntax error
 163.666 -
 163.667 -
 163.668 -
 163.669 -
 163.670 -
 163.671 -
 163.672 -Feather                     Standards Track                    [Page 12]
 163.673 -
 163.674 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.675 -
 163.676 -
 163.677 -   Example of a base64-encoding error (the second argument is meant to
 163.678 -   be base64 encoded):
 163.679 -
 163.680 -      [C] XENCRYPT RSA abcd=efg
 163.681 -      [S] 504 Base64 encoding error
 163.682 -
 163.683 -   Example of an attempt to access a facility not available to this
 163.684 -   connection:
 163.685 -
 163.686 -      [C] MODE READER
 163.687 -      [S] 200 Reader mode, posting permitted
 163.688 -      [C] IHAVE <i.am.an.article.you.will.want@example.com>
 163.689 -      [S] 500 Permission denied
 163.690 -
 163.691 -   Example of an attempt to access a facility requiring authentication:
 163.692 -
 163.693 -      [C] GROUP secret.group
 163.694 -      [S] 480 Permission denied
 163.695 -
 163.696 -   Example of a successful attempt following such authentication:
 163.697 -
 163.698 -      [C] XSECRET fred flintstone
 163.699 -      [S] 290 Password for fred accepted
 163.700 -      [C] GROUP secret.group
 163.701 -      [S] 211 5 1 20 secret.group selected
 163.702 -
 163.703 -   Example of an attempt to access a facility requiring privacy:
 163.704 -
 163.705 -      [C] GROUP secret.group
 163.706 -      [S] 483 Secure connection required
 163.707 -      [C] XENCRYPT
 163.708 -      [Client and server negotiate encryption on the link]
 163.709 -      [S] 283 Encrypted link established
 163.710 -      [C] GROUP secret.group
 163.711 -      [S] 211 5 1 20 secret.group selected
 163.712 -
 163.713 -   Example of a need to change mode before a facility is used:
 163.714 -
 163.715 -      [C] GROUP binary.group
 163.716 -      [S] 401 XHOST Not on this virtual host
 163.717 -      [C] XHOST binary.news.example.org
 163.718 -      [S] 290 binary.news.example.org virtual host selected
 163.719 -      [C] GROUP binary.group
 163.720 -      [S] 211 5 1 77 binary.group selected
 163.721 -
 163.722 -
 163.723 -
 163.724 -
 163.725 -
 163.726 -
 163.727 -
 163.728 -Feather                     Standards Track                    [Page 13]
 163.729 -
 163.730 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.731 -
 163.732 -
 163.733 -   Example of a temporary failure:
 163.734 -
 163.735 -      [C] GROUP archive.local
 163.736 -      [S] 403 Archive server temporarily offline
 163.737 -
 163.738 -   Example of the server needing to close down immediately:
 163.739 -
 163.740 -      [C] ARTICLE 123
 163.741 -      [S] 400 Power supply failed, running on UPS
 163.742 -      [Server closes connection.]
 163.743 -
 163.744 -3.3.  Capabilities and Extensions
 163.745 -
 163.746 -   Not all NNTP servers provide exactly the same facilities, both
 163.747 -   because this specification allows variation and because servers may
 163.748 -   provide extensions.  A set of facilities that are related are called
 163.749 -   a "capability".  This specification provides a way to determine what
 163.750 -   capabilities are available, includes a list of standard capabilities,
 163.751 -   and includes a mechanism (the extension mechanism) for defining new
 163.752 -   capabilities.
 163.753 -
 163.754 -3.3.1.  Capability Descriptions
 163.755 -
 163.756 -   A client can determine the available capabilities of the server by
 163.757 -   using the CAPABILITIES command (Section 5.2).  This returns a
 163.758 -   capability list, which is a list of capability lines.  Each line
 163.759 -   describes one available capability.
 163.760 -
 163.761 -   Each capability line consists of one or more tokens, which MUST be
 163.762 -   separated by one or more space or TAB characters.  A token is a
 163.763 -   string of 1 or more printable UTF-8 characters (that is, either
 163.764 -   printable US-ASCII characters or any UTF-8 sequence outside the US-
 163.765 -   ASCII range, but not space or TAB).  Unless stated otherwise, tokens
 163.766 -   are case insensitive.  Each capability line consists of the
 163.767 -   following:
 163.768 -
 163.769 -   o  The capability label, which is a keyword indicating the
 163.770 -      capability.  A capability label may be defined by this
 163.771 -      specification or a successor, or by an extension.
 163.772 -
 163.773 -   o  The label is then followed by zero or more tokens, which are
 163.774 -      arguments of the capability.  The form and meaning of these tokens
 163.775 -      is specific to each capability.
 163.776 -
 163.777 -   The server MUST ensure that the capability list accurately reflects
 163.778 -   the capabilities (including extensions) currently available.  If a
 163.779 -   capability is only available with the server in a certain state (for
 163.780 -   example, only after authentication), the list MUST only include the
 163.781 -
 163.782 -
 163.783 -
 163.784 -Feather                     Standards Track                    [Page 14]
 163.785 -
 163.786 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.787 -
 163.788 -
 163.789 -   capability label when the server is in that state.  Similarly, if
 163.790 -   only some of the commands in an extension will be available, or if
 163.791 -   the behaviour of the extension will change in some other manner,
 163.792 -   according to the state of the server, this MUST be indicated by
 163.793 -   different arguments in the capability line.
 163.794 -
 163.795 -   Note that a capability line can only begin with a letter.  Lines
 163.796 -   beginning with other characters are reserved for future versions of
 163.797 -   this specification.  In order to interoperate with such versions,
 163.798 -   clients MUST be prepared to receive lines beginning with other
 163.799 -   characters and MUST ignore any they do not understand.
 163.800 -
 163.801 -3.3.2.  Standard Capabilities
 163.802 -
 163.803 -   The following capabilities are defined by this specification.
 163.804 -
 163.805 -   VERSION
 163.806 -      This capability MUST be advertised by all servers and MUST be the
 163.807 -      first capability in the capability list; it indicates the
 163.808 -      version(s) of NNTP that the server supports.  There must be at
 163.809 -      least one argument; each argument is a decimal number and MUST NOT
 163.810 -      have a leading zero.  Version numbers are assigned only in RFCs
 163.811 -      that update or replace this specification; servers MUST NOT create
 163.812 -      their own version numbers.
 163.813 -
 163.814 -      The version number of this specification is 2.
 163.815 -
 163.816 -   READER
 163.817 -      This capability indicates that the server implements the various
 163.818 -      commands useful for reading clients.
 163.819 -
 163.820 -   IHAVE
 163.821 -      This capability indicates that the server implements the IHAVE
 163.822 -      command.
 163.823 -
 163.824 -   POST
 163.825 -      This capability indicates that the server implements the POST
 163.826 -      command.
 163.827 -
 163.828 -   NEWNEWS
 163.829 -      This capability indicates that the server implements the NEWNEWS
 163.830 -      command.
 163.831 -
 163.832 -   HDR
 163.833 -      This capability indicates that the server implements the header
 163.834 -      access commands (HDR and LIST HEADERS).
 163.835 -
 163.836 -
 163.837 -
 163.838 -
 163.839 -
 163.840 -Feather                     Standards Track                    [Page 15]
 163.841 -
 163.842 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.843 -
 163.844 -
 163.845 -   OVER
 163.846 -      This capability indicates that the server implements the overview
 163.847 -      access commands (OVER and LIST OVERVIEW.FMT).  If and only if the
 163.848 -      server supports the message-id form of the OVER command, there
 163.849 -      must be a single argument MSGID.
 163.850 -
 163.851 -   LIST
 163.852 -      This capability indicates that the server implements at least one
 163.853 -      variant of the LIST command.  There MUST be one argument for each
 163.854 -      variant of the LIST command supported by the server, giving the
 163.855 -      keyword for that variant.
 163.856 -
 163.857 -   IMPLEMENTATION
 163.858 -      This capability MAY be provided by a server.  If so, the arguments
 163.859 -      SHOULD be used to provide information such as the server software
 163.860 -      name and version number.  The client MUST NOT use this line to
 163.861 -      determine capabilities of the server.  (While servers often
 163.862 -      provide this information in the initial greeting, clients need to
 163.863 -      guess whether this is the case; this capability makes it clear
 163.864 -      what the information is.)
 163.865 -
 163.866 -   MODE-READER
 163.867 -      This capability indicates that the server is mode-switching
 163.868 -      (Section 3.4.2) and that the MODE READER command needs to be used
 163.869 -      to enable the READER capability.
 163.870 -
 163.871 -3.3.3.  Extensions
 163.872 -
 163.873 -   Although NNTP is widely and robustly deployed, some parts of the
 163.874 -   Internet community might wish to extend the NNTP service.  It must be
 163.875 -   emphasized that any extension to NNTP should not be considered
 163.876 -   lightly.  NNTP's strength comes primarily from its simplicity.
 163.877 -   Experience with many protocols has shown that:
 163.878 -
 163.879 -      Protocols with few options tend towards ubiquity, whilst protocols
 163.880 -      with many options tend towards obscurity.
 163.881 -
 163.882 -   This means that each and every extension, regardless of its benefits,
 163.883 -   must be carefully scrutinized with respect to its implementation,
 163.884 -   deployment, and interoperability costs.  In many cases, the cost of
 163.885 -   extending the NNTP service will likely outweigh the benefit.
 163.886 -
 163.887 -   An extension is a package of associated facilities, often but not
 163.888 -   always including one or more new commands.  Each extension MUST
 163.889 -   define at least one new capability label (this will often, but need
 163.890 -   not, be the name of one of these new commands).  While any additional
 163.891 -   capability information can normally be specified using arguments to
 163.892 -
 163.893 -
 163.894 -
 163.895 -
 163.896 -Feather                     Standards Track                    [Page 16]
 163.897 -
 163.898 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.899 -
 163.900 -
 163.901 -   that label, an extension MAY define more than one capability label.
 163.902 -   However, this SHOULD be limited to exceptional circumstances.
 163.903 -
 163.904 -   An extension is either a private extension, or its capabilities are
 163.905 -   included in the IANA registry of capabilities (see Section 3.3.4) and
 163.906 -   it is defined in an RFC (in which case it is a "registered
 163.907 -   extension").  Such RFCs either must be on the standards track or must
 163.908 -   define an IESG-approved experimental protocol.
 163.909 -
 163.910 -   The definition of an extension must include the following:
 163.911 -
 163.912 -   o  a descriptive name for the extension.
 163.913 -
 163.914 -   o  the capability label or labels defined by the extension (the
 163.915 -      capability label of a registered extension MUST NOT begin with
 163.916 -      "X").
 163.917 -
 163.918 -   o  The syntax, values, and meanings of any arguments for each
 163.919 -      capability label defined by the extension.
 163.920 -
 163.921 -   o  Any new NNTP commands associated with the extension (the names of
 163.922 -      commands associated with registered extensions MUST NOT begin with
 163.923 -      "X").
 163.924 -
 163.925 -   o  The syntax and possible values of arguments associated with the
 163.926 -      new NNTP commands.
 163.927 -
 163.928 -   o  The response codes and possible values of arguments for the
 163.929 -      responses of the new NNTP commands.
 163.930 -
 163.931 -   o  Any new arguments the extension associates with any other
 163.932 -      pre-existing NNTP commands.
 163.933 -
 163.934 -   o  Any increase in the maximum length of commands and initial
 163.935 -      response lines over the value specified in this document.
 163.936 -
 163.937 -   o  A specific statement about the effect on pipelining that this
 163.938 -      extension may have (if any).
 163.939 -
 163.940 -   o  A specific statement about the circumstances when use of this
 163.941 -      extension can alter the contents of the capabilities list (other
 163.942 -      than the new capability labels it defines).
 163.943 -
 163.944 -   o  A specific statement about the circumstances under which the
 163.945 -      extension can cause any pre-existing command to produce a 401,
 163.946 -      480, or 483 response.
 163.947 -
 163.948 -
 163.949 -
 163.950 -
 163.951 -
 163.952 -Feather                     Standards Track                    [Page 17]
 163.953 -
 163.954 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
 163.955 -
 163.956 -
 163.957 -   o  A description of how the use of MODE READER on a mode-switching
 163.958 -      server interacts with the extension.
 163.959 -
 163.960 -   o  A description of how support for the extension affects the
 163.961 -      behaviour of a server and NNTP client in any other manner not
 163.962 -      outlined above.
 163.963 -
 163.964 -   o  Formal syntax as described in Section 9.9.
 163.965 -
 163.966 -   A private extension MAY or MAY NOT be included in the capabilities
 163.967 -   list.  If it is, the capability label MUST begin with "X".  A server
 163.968 -   MAY provide additional keywords (for new commands and also for new
 163.969 -   variants of existing commands) as part of a private extension.  To
 163.970 -   avoid the risk of a clash with a future registered extension, these
 163.971 -   keywords SHOULD begin with "X".
 163.972 -
 163.973 -   If the server advertises a capability defined by a registered
 163.974 -   extension, it MUST implement the extension so as to fully conform
 163.975 -   with the specification (for example, it MUST implement all the
 163.976 -   commands that the extension describes as mandatory).  If it does not
 163.977 -   implement the extension as specified, it MUST NOT list the extension
 163.978 -   in the capabilities list under its registered name.  In that case, it
 163.979 -   MAY, but SHOULD NOT, provide a private extension (not listed, or
 163.980 -   listed with a different name) that implements part of the extension
 163.981 -   or implements the commands of the extension with a different meaning.
 163.982 -
 163.983 -   A server MUST NOT send different response codes to basic NNTP
 163.984 -   commands documented here or to commands documented in registered
 163.985 -   extensions in response to the availability or use of a private
 163.986 -   extension.
 163.987 -
 163.988 -3.3.4.  Initial IANA Register
 163.989 -
 163.990 -   IANA will maintain a registry of NNTP capability labels.  All
 163.991 -   capability labels in the registry MUST be keywords and MUST NOT begin
 163.992 -   with X.
 163.993 -
 163.994 -
 163.995 -
 163.996 -
 163.997 -
 163.998 -
 163.999 -
163.1000 -
163.1001 -
163.1002 -
163.1003 -
163.1004 -
163.1005 -
163.1006 -
163.1007 -
163.1008 -Feather                     Standards Track                    [Page 18]
163.1009 -
163.1010 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1011 -
163.1012 -
163.1013 -   The initial content of the registry consists of these entries:
163.1014 -
163.1015 -   +-------------------+--------------------------+--------------------+
163.1016 -   | Label             | Meaning                  | Definition         |
163.1017 -   +-------------------+--------------------------+--------------------+
163.1018 -   | AUTHINFO          | Authentication           | [NNTP-AUTH]        |
163.1019 -   |                   |                          |                    |
163.1020 -   | HDR               | Batched header retrieval | Section 3.3.2,     |
163.1021 -   |                   |                          | Section 8.5, and   |
163.1022 -   |                   |                          | Section 8.6        |
163.1023 -   |                   |                          |                    |
163.1024 -   | IHAVE             | IHAVE command available  | Section 3.3.2 and  |
163.1025 -   |                   |                          | Section 6.3.2      |
163.1026 -   |                   |                          |                    |
163.1027 -   | IMPLEMENTATION    | Server                   | Section 3.3.2      |
163.1028 -   |                   | implementation-specific  |                    |
163.1029 -   |                   | information              |                    |
163.1030 -   |                   |                          |                    |
163.1031 -   | LIST              | LIST command variants    | Section 3.3.2 and  |
163.1032 -   |                   |                          | Section 7.6.1      |
163.1033 -   |                   |                          |                    |
163.1034 -   | MODE-READER       | Mode-switching server    | Section 3.4.2      |
163.1035 -   |                   | and MODE READER command  |                    |
163.1036 -   |                   | available                |                    |
163.1037 -   |                   |                          |                    |
163.1038 -   | NEWNEWS           | NEWNEWS command          | Section 3.3.2 and  |
163.1039 -   |                   | available                | Section 7.4        |
163.1040 -   |                   |                          |                    |
163.1041 -   | OVER              | Overview support         | Section 3.3.2,     |
163.1042 -   |                   |                          | Section 8.3, and   |
163.1043 -   |                   |                          | Section 8.4        |
163.1044 -   |                   |                          |                    |
163.1045 -   | POST              | POST command available   | Section 3.3.2 and  |
163.1046 -   |                   |                          | Section 6.3.1      |
163.1047 -   |                   |                          |                    |
163.1048 -   | READER            | Reader commands          | Section 3.3.2      |
163.1049 -   |                   | available                |                    |
163.1050 -   |                   |                          |                    |
163.1051 -   | SASL              | Supported SASL           | [NNTP-AUTH]        |
163.1052 -   |                   | mechanisms               |                    |
163.1053 -   |                   |                          |                    |
163.1054 -   | STARTTLS          | Transport layer security | [NNTP-TLS]         |
163.1055 -   |                   |                          |                    |
163.1056 -   | STREAMING         | Streaming feeds          | [NNTP-STREAM]      |
163.1057 -   |                   |                          |                    |
163.1058 -   | VERSION           | Supported NNTP versions  | Section 3.3.2      |
163.1059 -   +-------------------+--------------------------+--------------------+
163.1060 -
163.1061 -
163.1062 -
163.1063 -
163.1064 -Feather                     Standards Track                    [Page 19]
163.1065 -
163.1066 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1067 -
163.1068 -
163.1069 -3.4.  Mandatory and Optional Commands
163.1070 -
163.1071 -   For a number of reasons, not all the commands in this specification
163.1072 -   are mandatory.  However, it is equally undesirable for every command
163.1073 -   to be optional, since this means that a client will have no idea what
163.1074 -   facilities are available.  Therefore, as a compromise, some of the
163.1075 -   commands in this specification are mandatory (they must be supported
163.1076 -   by all servers) while the remainder are not.  The latter are then
163.1077 -   subdivided into bundles, each indicated by a single capability label.
163.1078 -
163.1079 -   o  If the label is included in the capability list returned by the
163.1080 -      server, the server MUST support all commands in that bundle.
163.1081 -
163.1082 -   o  If the label is not included, the server MAY support none or some
163.1083 -      of the commands but SHOULD NOT support all of them.  In general,
163.1084 -      there will be no way for a client to determine which commands are
163.1085 -      supported without trying them.
163.1086 -
163.1087 -   The bundles have been chosen to provide useful functionality, and
163.1088 -   therefore server authors are discouraged from implementing only part
163.1089 -   of a bundle.
163.1090 -
163.1091 -   The description of each command will either indicate that it is
163.1092 -   mandatory, or will give, using the term "indicating capability", the
163.1093 -   capability label indicating whether the bundle including this command
163.1094 -   is available.
163.1095 -
163.1096 -   Where a server does not implement a command, it MUST always generate
163.1097 -   a 500 generic response code (or a 501 generic response code in the
163.1098 -   case of a variant of a command depending on a second keyword where
163.1099 -   the base command is recognised).  Otherwise, the command MUST be
163.1100 -   fully implemented as specified; a server MUST NOT only partially
163.1101 -   implement any of the commands in this specification.  (Client authors
163.1102 -   should note that some servers not conforming to this specification
163.1103 -   will return a 502 generic response code to some commands that are not
163.1104 -   implemented.)
163.1105 -
163.1106 -   Note: some commands have cases that require other commands to be used
163.1107 -   first.  If the former command is implemented but the latter is not,
163.1108 -   the former MUST still generate the relevant specific response code.
163.1109 -   For example, if ARTICLE (Section 6.2.1) is implemented but GROUP
163.1110 -   (Section 6.1.1) is not, the correct response to "ARTICLE 1234"
163.1111 -   remains 412.
163.1112 -
163.1113 -
163.1114 -
163.1115 -
163.1116 -
163.1117 -
163.1118 -
163.1119 -
163.1120 -Feather                     Standards Track                    [Page 20]
163.1121 -
163.1122 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1123 -
163.1124 -
163.1125 -3.4.1.  Reading and Transit Servers
163.1126 -
163.1127 -   NNTP is traditionally used in two different ways.  The first use is
163.1128 -   "reading", where the client fetches articles from a large store
163.1129 -   maintained by the server for immediate or later presentation to a
163.1130 -   user and sends articles created by that user back to the server (an
163.1131 -   action called "posting") to be stored and distributed to other stores
163.1132 -   and users.  The second use is for the bulk transfer of articles from
163.1133 -   one store to another.  Since the hosts making this transfer tend to
163.1134 -   be peers in a network that transmit articles among one another, and
163.1135 -   not end-user systems, this process is called "peering" or "transit".
163.1136 -   (Even so, one host is still the client and the other is the server).
163.1137 -
163.1138 -   In practice, these two uses are so different that some server
163.1139 -   implementations are optimised for reading or for transit and, as a
163.1140 -   result, do not offer the other facility or only offer limited
163.1141 -   features.  Other implementations are more general and offer both.
163.1142 -   This specification allows for this by bundling the relevant commands
163.1143 -   accordingly: the IHAVE command is designed for transit, while the
163.1144 -   commands indicated by the READER capability are designed for reading
163.1145 -   clients.
163.1146 -
163.1147 -   Except as an effect of the MODE READER command (Section 5.3) on a
163.1148 -   mode-switching server, once a server advertises either or both of the
163.1149 -   IHAVE or READER capabilities, it MUST continue to advertise them for
163.1150 -   the entire session.
163.1151 -
163.1152 -   A server MAY provide different modes of behaviour (transit, reader,
163.1153 -   or a combination) to different client connections and MAY use
163.1154 -   external information, such as the IP address of the client, to
163.1155 -   determine which mode to provide to any given connection.
163.1156 -
163.1157 -   The official TCP port for the NNTP service is 119.  However, if a
163.1158 -   host wishes to offer separate servers for transit and reading
163.1159 -   clients, port 433 SHOULD be used for the transit server and 119 for
163.1160 -   the reading server.
163.1161 -
163.1162 -3.4.2.  Mode Switching
163.1163 -
163.1164 -   An implementation MAY, but SHOULD NOT, provide both transit and
163.1165 -   reader facilities on the same server but require the client to select
163.1166 -   which it wishes to use.  Such an arrangement is called a
163.1167 -   "mode-switching" server.
163.1168 -
163.1169 -
163.1170 -
163.1171 -
163.1172 -
163.1173 -
163.1174 -
163.1175 -
163.1176 -Feather                     Standards Track                    [Page 21]
163.1177 -
163.1178 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1179 -
163.1180 -
163.1181 -   A mode-switching server has two modes:
163.1182 -
163.1183 -   o  Transit mode, which applies after the initial connection.
163.1184 -
163.1185 -      *  It MUST advertise the MODE-READER capability.
163.1186 -
163.1187 -      *  It MUST NOT advertise the READER capability.
163.1188 -
163.1189 -      However, the server MAY cease to advertise the MODE-READER
163.1190 -      capability after the client uses any command except CAPABILITIES.
163.1191 -
163.1192 -   o  Reading mode, after a successful MODE READER command (see Section
163.1193 -      5.3).
163.1194 -
163.1195 -      *  It MUST NOT advertise the MODE-READER capability.
163.1196 -
163.1197 -      *  It MUST advertise the READER capability.
163.1198 -
163.1199 -      *  It MAY NOT advertise the IHAVE capability, even if it was
163.1200 -         advertising it in transit mode.
163.1201 -
163.1202 -   A client SHOULD only issue a MODE READER command to a server if it is
163.1203 -   advertising the MODE-READER capability.  If the server does not
163.1204 -   support CAPABILITIES (and therefore does not conform to this
163.1205 -   specification), the client MAY use the following heuristic:
163.1206 -
163.1207 -   o  If the client wishes to use any "reader" commands, it SHOULD use
163.1208 -      the MODE READER command immediately after the initial connection.
163.1209 -
163.1210 -   o  Otherwise, it SHOULD NOT use the MODE READER command.
163.1211 -
163.1212 -   In each case, it should be prepared for some commands to be
163.1213 -   unavailable that would have been available if it had made the other
163.1214 -   choice.
163.1215 -
163.1216 -3.5.  Pipelining
163.1217 -
163.1218 -   NNTP is designed to operate over a reliable bi-directional
163.1219 -   connection, such as TCP.  Therefore, if a command does not depend on
163.1220 -   the response to the previous one, it should not matter if it is sent
163.1221 -   before that response is received.  Doing this is called "pipelining".
163.1222 -   However, certain server implementations throw away all text received
163.1223 -   from the client following certain commands before sending their
163.1224 -   response.  If this happens, pipelining will be affected because one
163.1225 -   or more commands will have been ignored or misinterpreted, and the
163.1226 -   client will be matching the wrong responses to each command.  Since
163.1227 -   there are significant benefits to pipelining, but also circumstances
163.1228 -   where it is reasonable or common for servers to behave in the above
163.1229 -
163.1230 -
163.1231 -
163.1232 -Feather                     Standards Track                    [Page 22]
163.1233 -
163.1234 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1235 -
163.1236 -
163.1237 -   manner, this document puts certain requirements on both clients and
163.1238 -   servers.
163.1239 -
163.1240 -   Except where stated otherwise, a client MAY use pipelining.  That is,
163.1241 -   it may send a command before receiving the response for the previous
163.1242 -   command.  The server MUST allow pipelining and MUST NOT throw away
163.1243 -   any text received after a command.  Irrespective of whether
163.1244 -   pipelining is used, the server MUST process commands in the order
163.1245 -   they are sent.
163.1246 -
163.1247 -   If the specific description of a command says it "MUST NOT be
163.1248 -   pipelined", that command MUST end any pipeline of commands.  That is,
163.1249 -   the client MUST NOT send any following command until it receives the
163.1250 -   CRLF at the end of the response from the command.  The server MAY
163.1251 -   ignore any data received after the command and before the CRLF at the
163.1252 -   end of the response is sent to the client.
163.1253 -
163.1254 -   The initial connection must not be part of a pipeline; that is, the
163.1255 -   client MUST NOT send any command until it receives the CRLF at the
163.1256 -   end of the greeting.
163.1257 -
163.1258 -   If the client uses blocking system calls to send commands, it MUST
163.1259 -   ensure that the amount of text sent in pipelining does not cause a
163.1260 -   deadlock between transmission and reception.  The amount of text
163.1261 -   involved will depend on window sizes in the transmission layer;
163.1262 -   typically, it is 4k octets for TCP.  (Since the server only sends
163.1263 -   data in response to commands from the client, the converse problem
163.1264 -   does not occur.)
163.1265 -
163.1266 -3.5.1.  Examples
163.1267 -
163.1268 -   Example of correct use of pipelining:
163.1269 -
163.1270 -      [C] GROUP misc.test
163.1271 -      [C] STAT
163.1272 -      [C] NEXT
163.1273 -      [S] 211 1234 3000234 3002322 misc.test
163.1274 -      [S] 223 3000234 <45223423@example.com> retrieved
163.1275 -      [S] 223 3000237 <668929@example.org> retrieved
163.1276 -
163.1277 -   Example of incorrect use of pipelining (the MODE READER command may
163.1278 -   not be pipelined):
163.1279 -
163.1280 -      [C] MODE READER
163.1281 -      [C] DATE
163.1282 -      [C] NEXT
163.1283 -      [S] 200 Server ready, posting allowed
163.1284 -      [S] 223 3000237 <668929@example.org> retrieved
163.1285 -
163.1286 -
163.1287 -
163.1288 -Feather                     Standards Track                    [Page 23]
163.1289 -
163.1290 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1291 -
163.1292 -
163.1293 -   The DATE command has been thrown away by the server, so there is no
163.1294 -   111 response to match it.
163.1295 -
163.1296 -3.6.  Articles
163.1297 -
163.1298 -   NNTP is intended to transfer articles between clients and servers.
163.1299 -   For the purposes of this specification, articles are required to
163.1300 -   conform to the rules in this section, and clients and servers MUST
163.1301 -   correctly process any article received from the other that does so.
163.1302 -   Note that this requirement applies only to the contents of
163.1303 -   communications over NNTP; it does not prevent the client or server
163.1304 -   from subsequently rejecting an article for reasons of local policy.
163.1305 -   Also see Appendix A for further restrictions on the format of
163.1306 -   articles in some uses of NNTP.
163.1307 -
163.1308 -   An article consists of two parts: the headers and the body.  They are
163.1309 -   separated by a single empty line, or in other words by two
163.1310 -   consecutive CRLF pairs (if there is more than one empty line, the
163.1311 -   second and subsequent ones are part of the body).  In order to meet
163.1312 -   the general requirements of NNTP, an article MUST NOT include the
163.1313 -   octet NUL, MUST NOT contain the octets LF and CR other than as part
163.1314 -   of a CRLF pair, and MUST end with a CRLF pair.  This specification
163.1315 -   puts no further restrictions on the body; in particular, it MAY be
163.1316 -   empty.
163.1317 -
163.1318 -   The headers of an article consist of one or more header lines.  Each
163.1319 -   header line consists of a header name, a colon, a space, the header
163.1320 -   content, and a CRLF, in that order.  The name consists of one or more
163.1321 -   printable US-ASCII characters other than colon and, for the purposes
163.1322 -   of this specification, is not case sensitive.  There MAY be more than
163.1323 -   one header line with the same name.  The content MUST NOT contain
163.1324 -   CRLF; it MAY be empty.  A header may be "folded"; that is, a CRLF
163.1325 -   pair may be placed before any TAB or space in the line.  There MUST
163.1326 -   still be some other octet between any two CRLF pairs in a header
163.1327 -   line.  (Note that folding means that the header line occupies more
163.1328 -   than one line when displayed or transmitted; nevertheless, it is
163.1329 -   still referred to as "a" header line.)  The presence or absence of
163.1330 -   folding does not affect the meaning of the header line; that is, the
163.1331 -   CRLF pairs introduced by folding are not considered part of the
163.1332 -   header content.  Header lines SHOULD NOT be folded before the space
163.1333 -   after the colon that follows the header name and SHOULD include at
163.1334 -   least one octet other than %x09 or %x20 between CRLF pairs.  However,
163.1335 -   if an article that fails to satisfy this requirement has been
163.1336 -   received from elsewhere, clients and servers MAY transfer it to each
163.1337 -   other without re-folding it.
163.1338 -
163.1339 -
163.1340 -
163.1341 -
163.1342 -
163.1343 -
163.1344 -Feather                     Standards Track                    [Page 24]
163.1345 -
163.1346 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1347 -
163.1348 -
163.1349 -   The content of a header SHOULD be in UTF-8.  However, if an
163.1350 -   implementation receives an article from elsewhere that uses octets in
163.1351 -   the range 128 to 255 in some other manner, it MAY pass it to a client
163.1352 -   or server without modification.  Therefore, implementations MUST be
163.1353 -   prepared to receive such headers, and data derived from them (e.g.,
163.1354 -   in the responses from the OVER command, Section 8.3), and MUST NOT
163.1355 -   assume that they are always UTF-8.  Any external processing of those
163.1356 -   headers, including identifying the encoding used, is outside the
163.1357 -   scope of this document.
163.1358 -
163.1359 -   Each article MUST have a unique message-id; two articles offered by
163.1360 -   an NNTP server MUST NOT have the same message-id.  For the purposes
163.1361 -   of this specification, message-ids are opaque strings that MUST meet
163.1362 -   the following requirements:
163.1363 -
163.1364 -   o  A message-id MUST begin with "<", end with ">", and MUST NOT
163.1365 -      contain the latter except at the end.
163.1366 -
163.1367 -   o  A message-id MUST be between 3 and 250 octets in length.
163.1368 -
163.1369 -   o  A message-id MUST NOT contain octets other than printable US-ASCII
163.1370 -      characters.
163.1371 -
163.1372 -   Two message-ids are the same if and only if they consist of the same
163.1373 -   sequence of octets.
163.1374 -
163.1375 -   This specification does not describe how the message-id of an article
163.1376 -   is determined.  If the server does not have any way to determine a
163.1377 -   message-id from the article itself, it MUST synthesize one (this
163.1378 -   specification does not require that the article be changed as a
163.1379 -   result).  See also Appendix A.2.
163.1380 -
163.1381 -4.  The WILDMAT Format
163.1382 -
163.1383 -   The WILDMAT format described here is based on the version first
163.1384 -   developed by Rich Salz [SALZ1992], which was in turn derived from the
163.1385 -   format used in the UNIX "find" command to articulate file names.  It
163.1386 -   was developed to provide a uniform mechanism for matching patterns in
163.1387 -   the same manner that the UNIX shell matches filenames.
163.1388 -
163.1389 -
163.1390 -
163.1391 -
163.1392 -
163.1393 -
163.1394 -
163.1395 -
163.1396 -
163.1397 -
163.1398 -
163.1399 -
163.1400 -Feather                     Standards Track                    [Page 25]
163.1401 -
163.1402 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1403 -
163.1404 -
163.1405 -4.1.  Wildmat Syntax
163.1406 -
163.1407 -   A wildmat is described by the following ABNF [RFC4234] syntax, which
163.1408 -   is an extract of that in Section 9.8.
163.1409 -
163.1410 -     wildmat = wildmat-pattern *("," ["!"] wildmat-pattern)
163.1411 -     wildmat-pattern = 1*wildmat-item
163.1412 -     wildmat-item = wildmat-exact / wildmat-wild
163.1413 -     wildmat-exact = %x22-29 / %x2B / %x2D-3E / %x40-5A / %x5E-7E /
163.1414 -          UTF8-non-ascii ; exclude ! * , ? [ \ ]
163.1415 -     wildmat-wild = "*" / "?"
163.1416 -
163.1417 -   Note: the characters ",", "\", "[", and "]" are not allowed in
163.1418 -   wildmats, while * and ? are always wildcards.  This should not be a
163.1419 -   problem, since these characters cannot occur in newsgroup names,
163.1420 -   which is the only current use of wildmats.  Backslash is commonly
163.1421 -   used to suppress the special meaning of characters, whereas brackets
163.1422 -   are used to introduce sets.  However, these usages are not universal,
163.1423 -   and interpretation of these characters in the context of UTF-8
163.1424 -   strings is potentially complex and differs from existing practice, so
163.1425 -   they were omitted from this specification.  A future extension to
163.1426 -   this specification may provide semantics for these characters.
163.1427 -
163.1428 -4.2.  Wildmat Semantics
163.1429 -
163.1430 -   A wildmat is tested against a string and either matches or does not
163.1431 -   match.  To do this, each constituent <wildmat-pattern> is matched
163.1432 -   against the string, and the rightmost pattern that matches is
163.1433 -   identified.  If that <wildmat-pattern> is not preceded with "!", the
163.1434 -   whole wildmat matches.  If it is preceded by "!", or if no <wildmat-
163.1435 -   pattern> matches, the whole wildmat does not match.
163.1436 -
163.1437 -   For example, consider the wildmat "a*,!*b,*c*":
163.1438 -
163.1439 -   o  The string "aaa" matches because the rightmost match is with "a*".
163.1440 -
163.1441 -   o  The string "abb" does not match because the rightmost match is
163.1442 -      with "*b".
163.1443 -
163.1444 -   o  The string "ccb" matches because the rightmost match is with
163.1445 -      "*c*".
163.1446 -
163.1447 -   o  The string "xxx" does not match because no <wildmat-pattern>
163.1448 -      matches.
163.1449 -
163.1450 -   A <wildmat-pattern> matches a string if the string can be broken into
163.1451 -   components, each of which matches the corresponding <wildmat-item> in
163.1452 -   the pattern.  The matches must be in the same order, and the whole
163.1453 -
163.1454 -
163.1455 -
163.1456 -Feather                     Standards Track                    [Page 26]
163.1457 -
163.1458 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1459 -
163.1460 -
163.1461 -   string must be used in the match.  The pattern is "anchored"; that
163.1462 -   is, the first and last characters in the string must match the first
163.1463 -   and last item, respectively (unless that item is an asterisk matching
163.1464 -   zero characters).
163.1465 -
163.1466 -   A <wildmat-exact> matches the same character (which may be more than
163.1467 -   one octet in UTF-8).
163.1468 -
163.1469 -   "?" matches exactly one character (which may be more than one octet).
163.1470 -
163.1471 -   "*" matches zero or more characters.  It can match an empty string,
163.1472 -   but it cannot match a subsequence of a UTF-8 sequence that is not
163.1473 -   aligned to the character boundaries.
163.1474 -
163.1475 -4.3.  Extensions
163.1476 -
163.1477 -   An NNTP server or extension MAY extend the syntax or semantics of
163.1478 -   wildmats provided that all wildmats that meet the requirements of
163.1479 -   Section 4.1 have the meaning ascribed to them by Section 4.2.  Future
163.1480 -   editions of this document may also extend wildmats.
163.1481 -
163.1482 -4.4.  Examples
163.1483 -
163.1484 -   In these examples, $ and @ are used to represent the two octets %xC2
163.1485 -   and %xA3, respectively; $@ is thus the UTF-8 encoding for the pound
163.1486 -   sterling symbol, shown as # in the descriptions.
163.1487 -
163.1488 -     Wildmat    Description of strings that match
163.1489 -       abc      The one string "abc"
163.1490 -       abc,def  The two strings "abc" and "def"
163.1491 -       $@       The one character string "#"
163.1492 -       a*       Any string that begins with "a"
163.1493 -       a*b      Any string that begins with "a" and ends with "b"
163.1494 -       a*,*b    Any string that begins with "a" or ends with "b"
163.1495 -       a*,!*b   Any string that begins with "a" and does not end with
163.1496 -                "b"
163.1497 -     a*,!*b,c*  Any string that begins with "a" and does not end with
163.1498 -                "b", and any string that begins with "c" no matter
163.1499 -                what it ends with
163.1500 -     a*,c*,!*b  Any string that begins with "a" or "c" and does not
163.1501 -                end with "b"
163.1502 -       ?a*      Any string with "a" as its second character
163.1503 -       ??a*     Any string with "a" as its third character
163.1504 -       *a?      Any string with "a" as its penultimate character
163.1505 -       *a??     Any string with "a" as its antepenultimate character
163.1506 -
163.1507 -
163.1508 -
163.1509 -
163.1510 -
163.1511 -
163.1512 -Feather                     Standards Track                    [Page 27]
163.1513 -
163.1514 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1515 -
163.1516 -
163.1517 -5.  Session Administration Commands
163.1518 -
163.1519 -5.1.  Initial Connection
163.1520 -
163.1521 -5.1.1.  Usage
163.1522 -
163.1523 -   This command MUST NOT be pipelined.
163.1524 -
163.1525 -   Responses [1]
163.1526 -     200    Service available, posting allowed
163.1527 -     201    Service available, posting prohibited
163.1528 -     400    Service temporarily unavailable [2]
163.1529 -     502    Service permanently unavailable [2]
163.1530 -
163.1531 -   [1] These are the only valid response codes for the initial greeting;
163.1532 -       the server MUST not return any other generic response code.
163.1533 -
163.1534 -   [2] Following a 400 or 502 response, the server MUST immediately
163.1535 -       close the connection.
163.1536 -
163.1537 -5.1.2.  Description
163.1538 -
163.1539 -   There is no command presented by the client upon initial connection
163.1540 -   to the server.  The server MUST present an appropriate response code
163.1541 -   as a greeting to the client.  This response informs the client
163.1542 -   whether service is available and whether the client is permitted to
163.1543 -   post.
163.1544 -
163.1545 -   If the server will accept further commands from the client including
163.1546 -   POST, the server MUST present a 200 greeting code.  If the server
163.1547 -   will accept further commands from the client, but the client is not
163.1548 -   authorized to post articles using the POST command, the server MUST
163.1549 -   present a 201 greeting code.
163.1550 -
163.1551 -   Otherwise, the server MUST present a 400 or 502 greeting code and
163.1552 -   then immediately close the connection. 400 SHOULD be used if the
163.1553 -   issue is only temporary (for example, because of load) and the client
163.1554 -   can expect to be able to connect successfully at some point in the
163.1555 -   future without making any changes. 502 MUST be used if the client is
163.1556 -   not permitted under any circumstances to interact with the server,
163.1557 -   and MAY be used if the server has insufficient information to
163.1558 -   determine whether the issue is temporary or permanent.
163.1559 -
163.1560 -   Note: the distinction between the 200 and 201 response codes has
163.1561 -   turned out in practice to be insufficient; for example, some servers
163.1562 -   do not allow posting until the client has authenticated, while other
163.1563 -   clients assume that a 201 response means that posting will never be
163.1564 -   possible even after authentication.  Therefore, clients SHOULD use
163.1565 -
163.1566 -
163.1567 -
163.1568 -Feather                     Standards Track                    [Page 28]
163.1569 -
163.1570 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1571 -
163.1572 -
163.1573 -   the CAPABILITIES command (Section 5.2) rather than rely on this
163.1574 -   response.
163.1575 -
163.1576 -5.1.3.  Examples
163.1577 -
163.1578 -   Example of a normal connection from an authorized client that then
163.1579 -   terminates the session (see Section 5.4):
163.1580 -
163.1581 -      [Initial connection set-up completed.]
163.1582 -      [S] 200 NNTP Service Ready, posting permitted
163.1583 -      [C] QUIT
163.1584 -      [S] 205 NNTP Service exits normally
163.1585 -      [Server closes connection.]
163.1586 -
163.1587 -   Example of a normal connection from an authorized client that is not
163.1588 -   permitted to post, which also immediately terminates the session:
163.1589 -
163.1590 -      [Initial connection set-up completed.]
163.1591 -      [S] 201 NNTP Service Ready, posting prohibited
163.1592 -      [C] QUIT
163.1593 -      [S] 205 NNTP Service exits normally
163.1594 -      [Server closes connection.]
163.1595 -
163.1596 -   Example of a normal connection from an unauthorized client:
163.1597 -
163.1598 -      [Initial connection set-up completed.]
163.1599 -      [S] 502 NNTP Service permanently unavailable
163.1600 -      [Server closes connection.]
163.1601 -
163.1602 -   Example of a connection from a client if the server is unable to
163.1603 -   provide service:
163.1604 -
163.1605 -      [Initial connection set-up completed.]
163.1606 -      [S] 400 NNTP Service temporarily unavailable
163.1607 -      [Server closes connection.]
163.1608 -
163.1609 -5.2.  CAPABILITIES
163.1610 -
163.1611 -5.2.1.  Usage
163.1612 -
163.1613 -   This command is mandatory.
163.1614 -
163.1615 -   Syntax
163.1616 -     CAPABILITIES [keyword]
163.1617 -
163.1618 -   Responses
163.1619 -     101    Capability list follows (multi-line)
163.1620 -
163.1621 -
163.1622 -
163.1623 -
163.1624 -Feather                     Standards Track                    [Page 29]
163.1625 -
163.1626 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1627 -
163.1628 -
163.1629 -   Parameters
163.1630 -     keyword    additional feature, see description
163.1631 -
163.1632 -5.2.2.  Description
163.1633 -
163.1634 -   The CAPABILITIES command allows a client to determine the
163.1635 -   capabilities of the server at any given time.
163.1636 -
163.1637 -   This command MAY be issued at any time; the server MUST NOT require
163.1638 -   it to be issued in order to make use of any capability.  The response
163.1639 -   generated by this command MAY change during a session because of
163.1640 -   other state information (which, in turn, may be changed by the
163.1641 -   effects of other commands or by external events).  An NNTP client is
163.1642 -   only able to get the current and correct information concerning
163.1643 -   available capabilities at any point during a session by issuing a
163.1644 -   CAPABILITIES command at that point of that session and processing the
163.1645 -   response.
163.1646 -
163.1647 -   The capability list is returned as a multi-line data block following
163.1648 -   the 101 response code.  Each capability is described by a separate
163.1649 -   capability line.  The server MUST NOT list the same capability twice
163.1650 -   in the response, even with different arguments.  Except that the
163.1651 -   VERSION capability MUST be the first line, the order in which the
163.1652 -   capability lines appears is not significant; the server need not even
163.1653 -   consistently return the same order.
163.1654 -
163.1655 -   While some capabilities are likely to be always available or never
163.1656 -   available, others (notably extensions) will appear and disappear
163.1657 -   depending on server state changes within the session or on external
163.1658 -   events between sessions.  An NNTP client MAY cache the results of
163.1659 -   this command, but MUST NOT rely on the correctness of any cached
163.1660 -   results, whether from earlier in this session or from a previous
163.1661 -   session, MUST cope gracefully with the cached status being out of
163.1662 -   date, and SHOULD (if caching results) provide a way to force the
163.1663 -   cached information to be refreshed.  Furthermore, a client MUST NOT
163.1664 -   use cached results in relation to security, privacy, and
163.1665 -   authentication extensions.  See Section 12.6 for further discussion
163.1666 -   of this topic.
163.1667 -
163.1668 -   The keyword argument is not used by this specification.  It is
163.1669 -   provided so that extensions or revisions to this specification can
163.1670 -   include extra features for this command without requiring the
163.1671 -   CAPABILITIES command to be used twice (once to determine if the extra
163.1672 -   features are available, and a second time to make use of them).  If
163.1673 -   the server does not recognise the argument (and it is a keyword), it
163.1674 -   MUST respond with the 101 response code as if the argument had been
163.1675 -   omitted.  If an argument is provided that the server does recognise,
163.1676 -   it MAY use the 101 response code or MAY use some other response code
163.1677 -
163.1678 -
163.1679 -
163.1680 -Feather                     Standards Track                    [Page 30]
163.1681 -
163.1682 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1683 -
163.1684 -
163.1685 -   (which will be defined in the specification of that feature).  If the
163.1686 -   argument is not a keyword, the 501 generic response code MUST be
163.1687 -   returned.  The server MUST NOT generate any other response code to
163.1688 -   the CAPABILITIES command.
163.1689 -
163.1690 -5.2.3.  Examples
163.1691 -
163.1692 -   Example of a minimal response (a read-only server):
163.1693 -
163.1694 -      [C] CAPABILITIES
163.1695 -      [S] 101 Capability list:
163.1696 -      [S] VERSION 2
163.1697 -      [S] READER
163.1698 -      [S] LIST ACTIVE NEWSGROUPS
163.1699 -      [S] .
163.1700 -
163.1701 -   Example of a response from a server that has a range of facilities
163.1702 -   and that also describes itself:
163.1703 -
163.1704 -      [C] CAPABILITIES
163.1705 -      [S] 101 Capability list:
163.1706 -      [S] VERSION 2
163.1707 -      [S] READER
163.1708 -      [S] IHAVE
163.1709 -      [S] POST
163.1710 -      [S] NEWNEWS
163.1711 -      [S] LIST ACTIVE NEWSGROUPS ACTIVE.TIMES OVERVIEW.FMT
163.1712 -      [S] IMPLEMENTATION INN 4.2 2004-12-25
163.1713 -      [S] OVER MSGID
163.1714 -      [S] STREAMING
163.1715 -      [S] XSECRET
163.1716 -      [S] .
163.1717 -
163.1718 -   Example of a server that supports more than one version of NNTP:
163.1719 -
163.1720 -      [C] CAPABILITIES
163.1721 -      [S] 101 Capability list:
163.1722 -      [S] VERSION 2 3
163.1723 -      [S] READER
163.1724 -      [S] LIST ACTIVE NEWSGROUPS
163.1725 -      [S] .
163.1726 -
163.1727 -
163.1728 -
163.1729 -
163.1730 -
163.1731 -
163.1732 -
163.1733 -
163.1734 -
163.1735 -
163.1736 -Feather                     Standards Track                    [Page 31]
163.1737 -
163.1738 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1739 -
163.1740 -
163.1741 -   Example of a client attempting to use a feature of the CAPABILITIES
163.1742 -   command that the server does not support:
163.1743 -
163.1744 -      [C] CAPABILITIES AUTOUPDATE
163.1745 -      [S] 101 Capability list:
163.1746 -      [S] VERSION 2
163.1747 -      [S] READER
163.1748 -      [S] IHAVE
163.1749 -      [S] LIST ACTIVE NEWSGROUPS OVERVIEW.FMT HEADERS
163.1750 -      [S] OVER MSGID
163.1751 -      [S] HDR
163.1752 -      [S] NEWNEWS
163.1753 -      [S] .
163.1754 -
163.1755 -5.3.  MODE READER
163.1756 -
163.1757 -5.3.1.  Usage
163.1758 -
163.1759 -   Indicating capability: MODE-READER
163.1760 -
163.1761 -   This command MUST NOT be pipelined.
163.1762 -
163.1763 -   Syntax
163.1764 -     MODE READER
163.1765 -
163.1766 -   Responses
163.1767 -     200    Posting allowed
163.1768 -     201    Posting prohibited
163.1769 -     502    Reading service permanently unavailable [1]
163.1770 -
163.1771 -   [1] Following a 502 response the server MUST immediately close the
163.1772 -       connection.
163.1773 -
163.1774 -5.3.2.  Description
163.1775 -
163.1776 -   The MODE READER command instructs a mode-switching server to switch
163.1777 -   modes, as described in Section 3.4.2.
163.1778 -
163.1779 -   If the server is mode-switching, it switches from its transit mode to
163.1780 -   its reader mode, indicating this by changing the capability list
163.1781 -   accordingly.  It MUST then return a 200 or 201 response with the same
163.1782 -   meaning as for the initial greeting (as described in Section 5.1.1).
163.1783 -   Note that the response need not be the same as that presented during
163.1784 -   the initial greeting.  The client MUST NOT issue MODE READER more
163.1785 -   than once in a session or after any security or privacy commands are
163.1786 -   issued.  When the MODE READER command is issued, the server MAY reset
163.1787 -   its state to that immediately after the initial connection before
163.1788 -   switching mode.
163.1789 -
163.1790 -
163.1791 -
163.1792 -Feather                     Standards Track                    [Page 32]
163.1793 -
163.1794 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1795 -
163.1796 -
163.1797 -   If the server is not mode-switching, then the following apply:
163.1798 -
163.1799 -   o  If it advertises the READER capability, it MUST return a 200 or
163.1800 -      201 response with the same meaning as for the initial greeting; in
163.1801 -      this case, the command MUST NOT affect the server state in any
163.1802 -      way.
163.1803 -
163.1804 -   o  If it does not advertise the READER capability, it MUST return a
163.1805 -      502 response and then immediately close the connection.
163.1806 -
163.1807 -5.3.3.  Examples
163.1808 -
163.1809 -   Example of use of the MODE READER command on a transit-only server
163.1810 -   (which therefore does not providing reading facilities):
163.1811 -
163.1812 -      [C] CAPABILITIES
163.1813 -      [S] 101 Capability list:
163.1814 -      [S] VERSION 2
163.1815 -      [S] IHAVE
163.1816 -      [S] .
163.1817 -      [C] MODE READER
163.1818 -      [S] 502 Transit service only
163.1819 -      [Server closes connection.]
163.1820 -
163.1821 -   Example of use of the MODE READER command on a server that provides
163.1822 -   reading facilities:
163.1823 -
163.1824 -      [C] CAPABILITIES
163.1825 -      [S] 101 Capability list:
163.1826 -      [S] VERSION 2
163.1827 -      [S] READER
163.1828 -      [S] LIST ACTIVE NEWSGROUPS
163.1829 -      [S] .
163.1830 -      [C] MODE READER
163.1831 -      [S] 200 Reader mode, posting permitted
163.1832 -      [C] IHAVE <i.am.an.article.you.have@example.com>
163.1833 -      [S] 500 Permission denied
163.1834 -      [C] GROUP misc.test
163.1835 -      [S] 211 1234 3000234 3002322 misc.test
163.1836 -
163.1837 -   Note that in both of these situations, the client SHOULD NOT use MODE
163.1838 -   READER.
163.1839 -
163.1840 -
163.1841 -
163.1842 -
163.1843 -
163.1844 -
163.1845 -
163.1846 -
163.1847 -
163.1848 -Feather                     Standards Track                    [Page 33]
163.1849 -
163.1850 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1851 -
163.1852 -
163.1853 -   Example of use of the MODE READER command on a mode-switching server:
163.1854 -
163.1855 -      [C] CAPABILITIES
163.1856 -      [S] 101 Capability list:
163.1857 -      [S] VERSION 2
163.1858 -      [S] IHAVE
163.1859 -      [S] MODE-READER
163.1860 -      [S] .
163.1861 -      [C] MODE READER
163.1862 -      [S] 200 Reader mode, posting permitted
163.1863 -      [C] CAPABILITIES
163.1864 -      [S] 101 Capability list:
163.1865 -      [S] VERSION 2
163.1866 -      [S] READER
163.1867 -      [S] NEWNEWS
163.1868 -      [S] LIST ACTIVE NEWSGROUPS
163.1869 -      [S] STARTTLS
163.1870 -      [S] .
163.1871 -
163.1872 -   In this case, the server offers (but does not require) TLS privacy in
163.1873 -   its reading mode but not in its transit mode.
163.1874 -
163.1875 -   Example of use of the MODE READER command where the client is not
163.1876 -   permitted to post:
163.1877 -
163.1878 -      [C] MODE READER
163.1879 -      [S] 201 NNTP Service Ready, posting prohibited
163.1880 -
163.1881 -5.4.  QUIT
163.1882 -
163.1883 -5.4.1.  Usage
163.1884 -
163.1885 -   This command is mandatory.
163.1886 -
163.1887 -   Syntax
163.1888 -     QUIT
163.1889 -
163.1890 -   Responses
163.1891 -     205    Connection closing
163.1892 -
163.1893 -5.4.2.  Description
163.1894 -
163.1895 -   The client uses the QUIT command to terminate the session.  The
163.1896 -   server MUST acknowledge the QUIT command and then close the
163.1897 -   connection to the client.  This is the preferred method for a client
163.1898 -   to indicate that it has finished all of its transactions with the
163.1899 -   NNTP server.
163.1900 -
163.1901 -
163.1902 -
163.1903 -
163.1904 -Feather                     Standards Track                    [Page 34]
163.1905 -
163.1906 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1907 -
163.1908 -
163.1909 -   If a client simply disconnects (or if the connection times out or
163.1910 -   some other fault occurs), the server MUST gracefully cease its
163.1911 -   attempts to service the client, disconnecting from its end if
163.1912 -   necessary.
163.1913 -
163.1914 -   The server MUST NOT generate any response code to the QUIT command
163.1915 -   other than 205 or, if any arguments are provided, 501.
163.1916 -
163.1917 -5.4.3.  Examples
163.1918 -
163.1919 -      [C] QUIT
163.1920 -      [S] 205 closing connection
163.1921 -      [Server closes connection.]
163.1922 -
163.1923 -6.  Article Posting and Retrieval
163.1924 -
163.1925 -   News-reading clients have available a variety of mechanisms to
163.1926 -   retrieve articles via NNTP.  The news articles are stored and indexed
163.1927 -   using three types of keys.  The first type of key is the message-id
163.1928 -   of an article and is globally unique.  The second type of key is
163.1929 -   composed of a newsgroup name and an article number within that
163.1930 -   newsgroup.  On a particular server, there MUST only be one article
163.1931 -   with a given number within any newsgroup, and an article MUST NOT
163.1932 -   have two different numbers in the same newsgroup.  An article can be
163.1933 -   cross-posted to multiple newsgroups, so there may be multiple keys
163.1934 -   that point to the same article on the same server; these MAY have
163.1935 -   different numbers in each newsgroup.  However, this type of key is
163.1936 -   not required to be globally unique, so the same key MAY refer to
163.1937 -   different articles on different servers.  (Note that the terms
163.1938 -   "group" and "newsgroup" are equivalent.)
163.1939 -
163.1940 -   The final type of key is the arrival timestamp, giving the time that
163.1941 -   the article arrived at the server.  The server MUST ensure that
163.1942 -   article numbers are issued in order of arrival timestamp; that is,
163.1943 -   articles arriving later MUST have higher numbers than those that
163.1944 -   arrive earlier.  The server SHOULD allocate the next sequential
163.1945 -   unused number to each new article.
163.1946 -
163.1947 -   Article numbers MUST lie between 1 and 2,147,483,647, inclusive.  The
163.1948 -   client and server MAY use leading zeroes in specifying article
163.1949 -   numbers but MUST NOT use more than 16 digits.  In some situations,
163.1950 -   the value zero replaces an article number to show some special
163.1951 -   situation.
163.1952 -
163.1953 -   Note that it is likely that the article number limit of 2,147,483,647
163.1954 -   will be increased by a future revision or extension to this
163.1955 -   specification.  While servers MUST NOT send article numbers greater
163.1956 -   than this current limit, client and server developers are advised to
163.1957 -
163.1958 -
163.1959 -
163.1960 -Feather                     Standards Track                    [Page 35]
163.1961 -
163.1962 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.1963 -
163.1964 -
163.1965 -   use internal structures and datatypes capable of handling larger
163.1966 -   values in anticipation of such a change.
163.1967 -
163.1968 -6.1.  Group and Article Selection
163.1969 -
163.1970 -   The following commands are used to set the "currently selected
163.1971 -   newsgroup" and the "current article number", which are used by
163.1972 -   various commands.  At the start of an NNTP session, both of these
163.1973 -   values are set to the special value "invalid".
163.1974 -
163.1975 -6.1.1.  GROUP
163.1976 -
163.1977 -6.1.1.1.  Usage
163.1978 -
163.1979 -   Indicating capability: READER
163.1980 -
163.1981 -   Syntax
163.1982 -     GROUP group
163.1983 -
163.1984 -   Responses
163.1985 -     211 number low high group     Group successfully selected
163.1986 -     411                           No such newsgroup
163.1987 -
163.1988 -   Parameters
163.1989 -     group     Name of newsgroup
163.1990 -     number    Estimated number of articles in the group
163.1991 -     low       Reported low water mark
163.1992 -     high      Reported high water mark
163.1993 -
163.1994 -6.1.1.2.  Description
163.1995 -
163.1996 -   The GROUP command selects a newsgroup as the currently selected
163.1997 -   newsgroup and returns summary information about it.
163.1998 -
163.1999 -   The required argument is the name of the newsgroup to be selected
163.2000 -   (e.g., "news.software.nntp").  A list of valid newsgroups may be
163.2001 -   obtained by using the LIST ACTIVE command (see Section 7.6.3).
163.2002 -
163.2003 -   The successful selection response will return the article numbers of
163.2004 -   the first and last articles in the group at the moment of selection
163.2005 -   (these numbers are referred to as the "reported low water mark" and
163.2006 -   the "reported high water mark") and an estimate of the number of
163.2007 -   articles in the group currently available.
163.2008 -
163.2009 -   If the group is not empty, the estimate MUST be at least the actual
163.2010 -   number of articles available and MUST be no greater than one more
163.2011 -   than the difference between the reported low and high water marks.
163.2012 -   (Some implementations will actually count the number of articles
163.2013 -
163.2014 -
163.2015 -
163.2016 -Feather                     Standards Track                    [Page 36]
163.2017 -
163.2018 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2019 -
163.2020 -
163.2021 -   currently stored.  Others will just subtract the low water mark from
163.2022 -   the high water mark and add one to get an estimate.)
163.2023 -
163.2024 -   If the group is empty, one of the following three situations will
163.2025 -   occur.  Clients MUST accept all three cases; servers MUST NOT
163.2026 -   represent an empty group in any other way.
163.2027 -
163.2028 -   o  The high water mark will be one less than the low water mark, and
163.2029 -      the estimated article count will be zero.  Servers SHOULD use this
163.2030 -      method to show an empty group.  This is the only time that the
163.2031 -      high water mark can be less than the low water mark.
163.2032 -
163.2033 -   o  All three numbers will be zero.
163.2034 -
163.2035 -   o  The high water mark is greater than or equal to the low water
163.2036 -      mark.  The estimated article count might be zero or non-zero; if
163.2037 -      it is non-zero, the same requirements apply as for a non-empty
163.2038 -      group.
163.2039 -
163.2040 -   The set of articles in a group may change after the GROUP command is
163.2041 -   carried out:
163.2042 -
163.2043 -   o  Articles may be removed from the group.
163.2044 -
163.2045 -   o  Articles may be reinstated in the group with the same article
163.2046 -      number, but those articles MUST have numbers no less than the
163.2047 -      reported low water mark (note that this is a reinstatement of the
163.2048 -      previous article, not a new article reusing the number).
163.2049 -
163.2050 -   o  New articles may be added with article numbers greater than the
163.2051 -      reported high water mark.  (If an article that was the one with
163.2052 -      the highest number has been removed and the high water mark has
163.2053 -      been adjusted accordingly, the next new article will not have the
163.2054 -      number one greater than the reported high water mark.)
163.2055 -
163.2056 -   Except when the group is empty and all three numbers are zero,
163.2057 -   whenever a subsequent GROUP command for the same newsgroup is issued,
163.2058 -   either by the same client or a different client, the reported low
163.2059 -   water mark in the response MUST be no less than that in any previous
163.2060 -   response for that newsgroup in this session, and it SHOULD be no less
163.2061 -   than that in any previous response for that newsgroup ever sent to
163.2062 -   any client.  Any failure to meet the latter condition SHOULD be
163.2063 -   transient only.  The client may make use of the low water mark to
163.2064 -   remove all remembered information about articles with lower numbers,
163.2065 -   as these will never recur.  This includes the situation when the high
163.2066 -   water mark is one less than the low water mark.  No similar
163.2067 -   assumption can be made about the high water mark, as this can
163.2068 -
163.2069 -
163.2070 -
163.2071 -
163.2072 -Feather                     Standards Track                    [Page 37]
163.2073 -
163.2074 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2075 -
163.2076 -
163.2077 -   decrease if an article is removed and then increase again if it is
163.2078 -   reinstated or if new articles arrive.
163.2079 -
163.2080 -   When a valid group is selected by means of this command, the
163.2081 -   currently selected newsgroup MUST be set to that group, and the
163.2082 -   current article number MUST be set to the first article in the group
163.2083 -   (this applies even if the group is already the currently selected
163.2084 -   newsgroup).  If an empty newsgroup is selected, the current article
163.2085 -   number is made invalid.  If an invalid group is specified, the
163.2086 -   currently selected newsgroup and current article number MUST NOT be
163.2087 -   changed.
163.2088 -
163.2089 -   The GROUP or LISTGROUP command (see Section 6.1.2) MUST be used by a
163.2090 -   client, and a successful response received, before any other command
163.2091 -   is used that depends on the value of the currently selected newsgroup
163.2092 -   or current article number.
163.2093 -
163.2094 -   If the group specified is not available on the server, a 411 response
163.2095 -   MUST be returned.
163.2096 -
163.2097 -6.1.1.3.  Examples
163.2098 -
163.2099 -   Example for a group known to the server:
163.2100 -
163.2101 -      [C] GROUP misc.test
163.2102 -      [S] 211 1234 3000234 3002322 misc.test
163.2103 -
163.2104 -   Example for a group unknown to the server:
163.2105 -
163.2106 -      [C] GROUP example.is.sob.bradner.or.barber
163.2107 -      [S] 411 example.is.sob.bradner.or.barber is unknown
163.2108 -
163.2109 -   Example of an empty group using the preferred response:
163.2110 -
163.2111 -      [C] GROUP example.currently.empty.newsgroup
163.2112 -      [S] 211 0 4000 3999 example.currently.empty.newsgroup
163.2113 -
163.2114 -   Example of an empty group using an alternative response:
163.2115 -
163.2116 -      [C] GROUP example.currently.empty.newsgroup
163.2117 -      [S] 211 0 0 0 example.currently.empty.newsgroup
163.2118 -
163.2119 -   Example of an empty group using a different alternative response:
163.2120 -
163.2121 -      [C] GROUP example.currently.empty.newsgroup
163.2122 -      [S] 211 0 4000 4321 example.currently.empty.newsgroup
163.2123 -
163.2124 -
163.2125 -
163.2126 -
163.2127 -
163.2128 -Feather                     Standards Track                    [Page 38]
163.2129 -
163.2130 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2131 -
163.2132 -
163.2133 -   Example reselecting the currently selected newsgroup:
163.2134 -
163.2135 -      [C] GROUP misc.test
163.2136 -      [S] 211 1234 234 567 misc.test
163.2137 -      [C] STAT 444
163.2138 -      [S] 223 444 <123456@example.net> retrieved
163.2139 -      [C] GROUP misc.test
163.2140 -      [S] 211 1234 234 567 misc.test
163.2141 -      [C] STAT
163.2142 -      [S] 223 234 <different@example.net> retrieved
163.2143 -
163.2144 -6.1.2.  LISTGROUP
163.2145 -
163.2146 -6.1.2.1.  Usage
163.2147 -
163.2148 -   Indicating capability: READER
163.2149 -
163.2150 -   Syntax
163.2151 -     LISTGROUP [group [range]]
163.2152 -
163.2153 -   Responses
163.2154 -     211 number low high group     Article numbers follow (multi-line)
163.2155 -     411                           No such newsgroup
163.2156 -     412                           No newsgroup selected [1]
163.2157 -
163.2158 -   Parameters
163.2159 -     group     Name of newsgroup
163.2160 -     range     Range of articles to report
163.2161 -     number    Estimated number of articles in the group
163.2162 -     low       Reported low water mark
163.2163 -     high      Reported high water mark
163.2164 -
163.2165 -   [1] The 412 response can only occur if no group has been specified.
163.2166 -
163.2167 -6.1.2.2.  Description
163.2168 -
163.2169 -   The LISTGROUP command selects a newsgroup in the same manner as the
163.2170 -   GROUP command (see Section 6.1.1) but also provides a list of article
163.2171 -   numbers in the newsgroup.  If no group is specified, the currently
163.2172 -   selected newsgroup is used.
163.2173 -
163.2174 -   On success, a list of article numbers is returned as a multi-line
163.2175 -   data block following the 211 response code (the arguments on the
163.2176 -   initial response line are the same as for the GROUP command).  The
163.2177 -   list contains one number per line and is in numerical order.  It
163.2178 -   lists precisely those articles that exist in the group at the moment
163.2179 -   of selection (therefore, an empty group produces an empty list).  If
163.2180 -   the optional range argument is specified, only articles within the
163.2181 -
163.2182 -
163.2183 -
163.2184 -Feather                     Standards Track                    [Page 39]
163.2185 -
163.2186 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2187 -
163.2188 -
163.2189 -   range are included in the list (therefore, the list MAY be empty even
163.2190 -   if the group is not).
163.2191 -
163.2192 -   The range argument may be any of the following:
163.2193 -
163.2194 -   o  An article number.
163.2195 -
163.2196 -   o  An article number followed by a dash to indicate all following.
163.2197 -
163.2198 -   o  An article number followed by a dash followed by another article
163.2199 -      number.
163.2200 -
163.2201 -   In the last case, if the second number is less than the first number,
163.2202 -   then the range contains no articles.  Omitting the range is
163.2203 -   equivalent to the range 1- being specified.
163.2204 -
163.2205 -   If the group specified is not available on the server, a 411 response
163.2206 -   MUST be returned.  If no group is specified and the currently
163.2207 -   selected newsgroup is invalid, a 412 response MUST be returned.
163.2208 -
163.2209 -   Except that the group argument is optional, that a range argument can
163.2210 -   be specified, and that a multi-line data block follows the 211
163.2211 -   response code, the LISTGROUP command is identical to the GROUP
163.2212 -   command.  In particular, when successful, the command sets the
163.2213 -   current article number to the first article in the group, if any,
163.2214 -   even if this is not within the range specified by the second
163.2215 -   argument.
163.2216 -
163.2217 -   Note that the range argument is a new feature in this specification
163.2218 -   and servers that do not support CAPABILITIES (and therefore do not
163.2219 -   conform to this specification) are unlikely to support it.
163.2220 -
163.2221 -6.1.2.3.  Examples
163.2222 -
163.2223 -   Example of LISTGROUP being used to select a group:
163.2224 -
163.2225 -      [C] LISTGROUP misc.test
163.2226 -      [S] 211 2000 3000234 3002322 misc.test list follows
163.2227 -      [S] 3000234
163.2228 -      [S] 3000237
163.2229 -      [S] 3000238
163.2230 -      [S] 3000239
163.2231 -      [S] 3002322
163.2232 -      [S] .
163.2233 -
163.2234 -
163.2235 -
163.2236 -
163.2237 -
163.2238 -
163.2239 -
163.2240 -Feather                     Standards Track                    [Page 40]
163.2241 -
163.2242 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2243 -
163.2244 -
163.2245 -   Example of LISTGROUP on an empty group:
163.2246 -
163.2247 -      [C] LISTGROUP example.empty.newsgroup
163.2248 -      [S] 211 0 0 0 example.empty.newsgroup list follows
163.2249 -      [S] .
163.2250 -
163.2251 -   Example of LISTGROUP on a valid, currently selected newsgroup:
163.2252 -
163.2253 -      [C] GROUP misc.test
163.2254 -      [S] 211 2000 3000234 3002322 misc.test
163.2255 -      [C] LISTGROUP
163.2256 -      [S] 211 2000 3000234 3002322 misc.test list follows
163.2257 -      [S] 3000234
163.2258 -      [S] 3000237
163.2259 -      [S] 3000238
163.2260 -      [S] 3000239
163.2261 -      [S] 3002322
163.2262 -      [S] .
163.2263 -
163.2264 -   Example of LISTGROUP with a range:
163.2265 -
163.2266 -      [C] LISTGROUP misc.test 3000238-3000248
163.2267 -      [S] 211 2000 3000234 3002322 misc.test list follows
163.2268 -      [S] 3000238
163.2269 -      [S] 3000239
163.2270 -      [S] .
163.2271 -
163.2272 -   Example of LISTGROUP with an empty range:
163.2273 -
163.2274 -      [C] LISTGROUP misc.test 12345678-
163.2275 -      [S] 211 2000 3000234 3002322 misc.test list follows
163.2276 -      [S] .
163.2277 -
163.2278 -   Example of LISTGROUP with an invalid range:
163.2279 -
163.2280 -      [C] LISTGROUP misc.test 9999-111
163.2281 -      [S] 211 2000 3000234 3002322 misc.test list follows
163.2282 -      [S] .
163.2283 -
163.2284 -
163.2285 -
163.2286 -
163.2287 -
163.2288 -
163.2289 -
163.2290 -
163.2291 -
163.2292 -
163.2293 -
163.2294 -
163.2295 -
163.2296 -Feather                     Standards Track                    [Page 41]
163.2297 -
163.2298 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2299 -
163.2300 -
163.2301 -6.1.3.  LAST
163.2302 -
163.2303 -6.1.3.1.  Usage
163.2304 -
163.2305 -   Indicating capability: READER
163.2306 -
163.2307 -   Syntax
163.2308 -     LAST
163.2309 -
163.2310 -   Responses
163.2311 -     223 n message-id    Article found
163.2312 -     412                 No newsgroup selected
163.2313 -     420                 Current article number is invalid
163.2314 -     422                 No previous article in this group
163.2315 -
163.2316 -   Parameters
163.2317 -     n             Article number
163.2318 -     message-id    Article message-id
163.2319 -
163.2320 -6.1.3.2.  Description
163.2321 -
163.2322 -   If the currently selected newsgroup is valid, the current article
163.2323 -   number MUST be set to the previous article in that newsgroup (that
163.2324 -   is, the highest existing article number less than the current article
163.2325 -   number).  If successful, a response indicating the new current
163.2326 -   article number and the message-id of that article MUST be returned.
163.2327 -   No article text is sent in response to this command.
163.2328 -
163.2329 -   There MAY be no previous article in the group, although the current
163.2330 -   article number is not the reported low water mark.  There MUST NOT be
163.2331 -   a previous article when the current article number is the reported
163.2332 -   low water mark.
163.2333 -
163.2334 -   Because articles can be removed and added, the results of multiple
163.2335 -   LAST and NEXT commands MAY not be consistent over the life of a
163.2336 -   particular NNTP session.
163.2337 -
163.2338 -   If the current article number is already the first article of the
163.2339 -   newsgroup, a 422 response MUST be returned.  If the current article
163.2340 -   number is invalid, a 420 response MUST be returned.  If the currently
163.2341 -   selected newsgroup is invalid, a 412 response MUST be returned.  In
163.2342 -   all three cases, the currently selected newsgroup and current article
163.2343 -   number MUST NOT be altered.
163.2344 -
163.2345 -
163.2346 -
163.2347 -
163.2348 -
163.2349 -
163.2350 -
163.2351 -
163.2352 -Feather                     Standards Track                    [Page 42]
163.2353 -
163.2354 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2355 -
163.2356 -
163.2357 -6.1.3.3.  Examples
163.2358 -
163.2359 -   Example of a successful article retrieval using LAST:
163.2360 -
163.2361 -      [C] GROUP misc.test
163.2362 -      [S] 211 1234 3000234 3002322 misc.test
163.2363 -      [C] NEXT
163.2364 -      [S] 223 3000237 <668929@example.org> retrieved
163.2365 -      [C] LAST
163.2366 -      [S] 223 3000234 <45223423@example.com> retrieved
163.2367 -
163.2368 -   Example of an attempt to retrieve an article without having selected
163.2369 -   a group (via the GROUP command) first:
163.2370 -
163.2371 -      [Assumes currently selected newsgroup is invalid.]
163.2372 -      [C] LAST
163.2373 -      [S] 412 no newsgroup selected
163.2374 -
163.2375 -   Example of an attempt to retrieve an article using the LAST command
163.2376 -   when the current article number is that of the first article in the
163.2377 -   group:
163.2378 -
163.2379 -      [C] GROUP misc.test
163.2380 -      [S] 211 1234 3000234 3002322 misc.test
163.2381 -      [C] LAST
163.2382 -      [S] 422 No previous article to retrieve
163.2383 -
163.2384 -   Example of an attempt to retrieve an article using the LAST command
163.2385 -   when the currently selected newsgroup is empty:
163.2386 -
163.2387 -      [C] GROUP example.empty.newsgroup
163.2388 -      [S] 211 0 0 0 example.empty.newsgroup
163.2389 -      [C] LAST
163.2390 -      [S] 420 No current article selected
163.2391 -
163.2392 -
163.2393 -
163.2394 -
163.2395 -
163.2396 -
163.2397 -
163.2398 -
163.2399 -
163.2400 -
163.2401 -
163.2402 -
163.2403 -
163.2404 -
163.2405 -
163.2406 -
163.2407 -
163.2408 -Feather                     Standards Track                    [Page 43]
163.2409 -
163.2410 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2411 -
163.2412 -
163.2413 -6.1.4.  NEXT
163.2414 -
163.2415 -6.1.4.1.  Usage
163.2416 -
163.2417 -   Indicating capability: READER
163.2418 -
163.2419 -   Syntax
163.2420 -     NEXT
163.2421 -
163.2422 -   Responses
163.2423 -     223 n message-id    Article found
163.2424 -     412                 No newsgroup selected
163.2425 -     420                 Current article number is invalid
163.2426 -     421                 No next article in this group
163.2427 -
163.2428 -   Parameters
163.2429 -     n             Article number
163.2430 -     message-id    Article message-id
163.2431 -
163.2432 -6.1.4.2.  Description
163.2433 -
163.2434 -   If the currently selected newsgroup is valid, the current article
163.2435 -   number MUST be set to the next article in that newsgroup (that is,
163.2436 -   the lowest existing article number greater than the current article
163.2437 -   number).  If successful, a response indicating the new current
163.2438 -   article number and the message-id of that article MUST be returned.
163.2439 -   No article text is sent in response to this command.
163.2440 -
163.2441 -   If the current article number is already the last article of the
163.2442 -   newsgroup, a 421 response MUST be returned.  In all other aspects
163.2443 -   (apart, of course, from the lack of 422 response), this command is
163.2444 -   identical to the LAST command (Section 6.1.3).
163.2445 -
163.2446 -6.1.4.3.  Examples
163.2447 -
163.2448 -   Example of a successful article retrieval using NEXT:
163.2449 -
163.2450 -      [C] GROUP misc.test
163.2451 -      [S] 211 1234 3000234 3002322 misc.test
163.2452 -      [C] NEXT
163.2453 -      [S] 223 3000237 <668929@example.org> retrieved
163.2454 -
163.2455 -
163.2456 -
163.2457 -
163.2458 -
163.2459 -
163.2460 -
163.2461 -
163.2462 -
163.2463 -
163.2464 -Feather                     Standards Track                    [Page 44]
163.2465 -
163.2466 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2467 -
163.2468 -
163.2469 -   Example of an attempt to retrieve an article without having selected
163.2470 -   a group (via the GROUP command) first:
163.2471 -
163.2472 -      [Assumes currently selected newsgroup is invalid.]
163.2473 -      [C] NEXT
163.2474 -      [S] 412 no newsgroup selected
163.2475 -
163.2476 -   Example of an attempt to retrieve an article using the NEXT command
163.2477 -   when the current article number is that of the last article in the
163.2478 -   group:
163.2479 -
163.2480 -      [C] GROUP misc.test
163.2481 -      [S] 211 1234 3000234 3002322 misc.test
163.2482 -      [C] STAT 3002322
163.2483 -      [S] 223 3002322 <411@example.net> retrieved
163.2484 -      [C] NEXT
163.2485 -      [S] 421 No next article to retrieve
163.2486 -
163.2487 -   Example of an attempt to retrieve an article using the NEXT command
163.2488 -   when the currently selected newsgroup is empty:
163.2489 -
163.2490 -      [C] GROUP example.empty.newsgroup
163.2491 -      [S] 211 0 0 0 example.empty.newsgroup
163.2492 -      [C] NEXT
163.2493 -      [S] 420 No current article selected
163.2494 -
163.2495 -6.2.  Retrieval of Articles and Article Sections
163.2496 -
163.2497 -   The ARTICLE, BODY, HEAD, and STAT commands are very similar.  They
163.2498 -   differ only in the parts of the article that are presented to the
163.2499 -   client and in the successful response code.  The ARTICLE command is
163.2500 -   described here in full, while the other three commands are described
163.2501 -   in terms of the differences.  As specified in Section 3.6, an article
163.2502 -   consists of two parts: the article headers and the article body.
163.2503 -
163.2504 -   When responding to one of these commands, the server MUST present the
163.2505 -   entire article or appropriate part and MUST NOT attempt to alter or
163.2506 -   translate it in any way.
163.2507 -
163.2508 -
163.2509 -
163.2510 -
163.2511 -
163.2512 -
163.2513 -
163.2514 -
163.2515 -
163.2516 -
163.2517 -
163.2518 -
163.2519 -
163.2520 -Feather                     Standards Track                    [Page 45]
163.2521 -
163.2522 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2523 -
163.2524 -
163.2525 -6.2.1.  ARTICLE
163.2526 -
163.2527 -6.2.1.1.  Usage
163.2528 -
163.2529 -   Indicating capability: READER
163.2530 -
163.2531 -   Syntax
163.2532 -     ARTICLE message-id
163.2533 -     ARTICLE number
163.2534 -     ARTICLE
163.2535 -
163.2536 -   Responses
163.2537 -
163.2538 -   First form (message-id specified)
163.2539 -     220 0|n message-id    Article follows (multi-line)
163.2540 -     430                   No article with that message-id
163.2541 -
163.2542 -   Second form (article number specified)
163.2543 -     220 n message-id      Article follows (multi-line)
163.2544 -     412                   No newsgroup selected
163.2545 -     423                   No article with that number
163.2546 -
163.2547 -   Third form (current article number used)
163.2548 -     220 n message-id      Article follows (multi-line)
163.2549 -     412                   No newsgroup selected
163.2550 -     420                   Current article number is invalid
163.2551 -
163.2552 -   Parameters
163.2553 -     number        Requested article number
163.2554 -     n             Returned article number
163.2555 -     message-id    Article message-id
163.2556 -
163.2557 -6.2.1.2.  Description
163.2558 -
163.2559 -   The ARTICLE command selects an article according to the arguments and
163.2560 -   presents the entire article (that is, the headers, an empty line, and
163.2561 -   the body, in that order) to the client.  The command has three forms.
163.2562 -
163.2563 -   In the first form, a message-id is specified, and the server presents
163.2564 -   the article with that message-id.  In this case, the server MUST NOT
163.2565 -   alter the currently selected newsgroup or current article number.
163.2566 -   This is both to facilitate the presentation of articles that may be
163.2567 -   referenced within another article being read, and because of the
163.2568 -   semantic difficulties of determining the proper sequence and
163.2569 -   membership of an article that may have been cross-posted to more than
163.2570 -   one newsgroup.
163.2571 -
163.2572 -
163.2573 -
163.2574 -
163.2575 -
163.2576 -Feather                     Standards Track                    [Page 46]
163.2577 -
163.2578 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2579 -
163.2580 -
163.2581 -   In the response, the article number MUST be replaced with zero,
163.2582 -   unless there is a currently selected newsgroup and the article is
163.2583 -   present in that group, in which case the server MAY use the article's
163.2584 -   number in that group.  (The server is not required to determine
163.2585 -   whether the article is in the currently selected newsgroup or, if so,
163.2586 -   what article number it has; the client MUST always be prepared for
163.2587 -   zero to be specified.)  The server MUST NOT provide an article number
163.2588 -   unless use of that number in a second ARTICLE command immediately
163.2589 -   following this one would return the same article.  Even if the server
163.2590 -   chooses to return article numbers in these circumstances, it need not
163.2591 -   do so consistently; it MAY return zero to any such command (also see
163.2592 -   the STAT examples, Section 6.2.4.3).
163.2593 -
163.2594 -   In the second form, an article number is specified.  If there is an
163.2595 -   article with that number in the currently selected newsgroup, the
163.2596 -   server MUST set the current article number to that number.
163.2597 -
163.2598 -   In the third form, the article indicated by the current article
163.2599 -   number in the currently selected newsgroup is used.
163.2600 -
163.2601 -   Note that a previously valid article number MAY become invalid if the
163.2602 -   article has been removed.  A previously invalid article number MAY
163.2603 -   become valid if the article has been reinstated, but this article
163.2604 -   number MUST be no less than the reported low water mark for that
163.2605 -   group.
163.2606 -
163.2607 -   The server MUST NOT change the currently selected newsgroup as a
163.2608 -   result of this command.  The server MUST NOT change the current
163.2609 -   article number except when an article number argument was provided
163.2610 -   and the article exists; in particular, it MUST NOT change it
163.2611 -   following an unsuccessful response.
163.2612 -
163.2613 -   Since the message-id is unique for each article, it may be used by a
163.2614 -   client to skip duplicate displays of articles that have been posted
163.2615 -   more than once, or to more than one newsgroup.
163.2616 -
163.2617 -   The article is returned as a multi-line data block following the 220
163.2618 -   response code.
163.2619 -
163.2620 -   If the argument is a message-id and no such article exists, a 430
163.2621 -   response MUST be returned.  If the argument is a number or is omitted
163.2622 -   and the currently selected newsgroup is invalid, a 412 response MUST
163.2623 -   be returned.  If the argument is a number and that article does not
163.2624 -   exist in the currently selected newsgroup, a 423 response MUST be
163.2625 -   returned.  If the argument is omitted and the current article number
163.2626 -   is invalid, a 420 response MUST be returned.
163.2627 -
163.2628 -
163.2629 -
163.2630 -
163.2631 -
163.2632 -Feather                     Standards Track                    [Page 47]
163.2633 -
163.2634 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2635 -
163.2636 -
163.2637 -6.2.1.3.  Examples
163.2638 -
163.2639 -   Example of a successful retrieval of an article (explicitly not using
163.2640 -   an article number):
163.2641 -
163.2642 -      [C] GROUP misc.test
163.2643 -      [S] 211 1234 3000234 3002322 misc.test
163.2644 -      [C] ARTICLE
163.2645 -      [S] 220 3000234 <45223423@example.com>
163.2646 -      [S] Path: pathost!demo!whitehouse!not-for-mail
163.2647 -      [S] From: "Demo User" <nobody@example.net>
163.2648 -      [S] Newsgroups: misc.test
163.2649 -      [S] Subject: I am just a test article
163.2650 -      [S] Date: 6 Oct 1998 04:38:40 -0500
163.2651 -      [S] Organization: An Example Net, Uncertain, Texas
163.2652 -      [S] Message-ID: <45223423@example.com>
163.2653 -      [S]
163.2654 -      [S] This is just a test article.
163.2655 -      [S] .
163.2656 -
163.2657 -   Example of a successful retrieval of an article by message-id:
163.2658 -
163.2659 -      [C] ARTICLE <45223423@example.com>
163.2660 -      [S] 220 0 <45223423@example.com>
163.2661 -      [S] Path: pathost!demo!whitehouse!not-for-mail
163.2662 -      [S] From: "Demo User" <nobody@example.net>
163.2663 -      [S] Newsgroups: misc.test
163.2664 -      [S] Subject: I am just a test article
163.2665 -      [S] Date: 6 Oct 1998 04:38:40 -0500
163.2666 -      [S] Organization: An Example Net, Uncertain, Texas
163.2667 -      [S] Message-ID: <45223423@example.com>
163.2668 -      [S]
163.2669 -      [S] This is just a test article.
163.2670 -      [S] .
163.2671 -
163.2672 -   Example of an unsuccessful retrieval of an article by message-id:
163.2673 -
163.2674 -      [C] ARTICLE <i.am.not.there@example.com>
163.2675 -      [S] 430 No Such Article Found
163.2676 -
163.2677 -   Example of an unsuccessful retrieval of an article by number:
163.2678 -
163.2679 -      [C] GROUP misc.test
163.2680 -      [S] 211 1234 3000234 3002322 news.groups
163.2681 -      [C] ARTICLE 300256
163.2682 -      [S] 423 No article with that number
163.2683 -
163.2684 -
163.2685 -
163.2686 -
163.2687 -
163.2688 -Feather                     Standards Track                    [Page 48]
163.2689 -
163.2690 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2691 -
163.2692 -
163.2693 -   Example of an unsuccessful retrieval of an article by number because
163.2694 -   no newsgroup was selected first:
163.2695 -
163.2696 -      [Assumes currently selected newsgroup is invalid.]
163.2697 -      [C] ARTICLE 300256
163.2698 -      [S] 412 No newsgroup selected
163.2699 -
163.2700 -   Example of an attempt to retrieve an article when the currently
163.2701 -   selected newsgroup is empty:
163.2702 -
163.2703 -      [C] GROUP example.empty.newsgroup
163.2704 -      [S] 211 0 0 0 example.empty.newsgroup
163.2705 -      [C] ARTICLE
163.2706 -      [S] 420 No current article selected
163.2707 -
163.2708 -6.2.2.  HEAD
163.2709 -
163.2710 -6.2.2.1.  Usage
163.2711 -
163.2712 -   This command is mandatory.
163.2713 -
163.2714 -   Syntax
163.2715 -     HEAD message-id
163.2716 -     HEAD number
163.2717 -     HEAD
163.2718 -
163.2719 -   Responses
163.2720 -
163.2721 -   First form (message-id specified)
163.2722 -     221 0|n message-id    Headers follow (multi-line)
163.2723 -     430                   No article with that message-id
163.2724 -
163.2725 -   Second form (article number specified)
163.2726 -     221 n message-id      Headers follow (multi-line)
163.2727 -     412                   No newsgroup selected
163.2728 -     423                   No article with that number
163.2729 -
163.2730 -   Third form (current article number used)
163.2731 -     221 n message-id      Headers follow (multi-line)
163.2732 -     412                   No newsgroup selected
163.2733 -     420                   Current article number is invalid
163.2734 -
163.2735 -   Parameters
163.2736 -     number        Requested article number
163.2737 -     n             Returned article number
163.2738 -     message-id    Article message-id
163.2739 -
163.2740 -
163.2741 -
163.2742 -
163.2743 -
163.2744 -Feather                     Standards Track                    [Page 49]
163.2745 -
163.2746 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2747 -
163.2748 -
163.2749 -6.2.2.2.  Description
163.2750 -
163.2751 -   The HEAD command behaves identically to the ARTICLE command except
163.2752 -   that, if the article exists, the response code is 221 instead of 220
163.2753 -   and only the headers are presented (the empty line separating the
163.2754 -   headers and body MUST NOT be included).
163.2755 -
163.2756 -6.2.2.3.  Examples
163.2757 -
163.2758 -   Example of a successful retrieval of the headers of an article
163.2759 -   (explicitly not using an article number):
163.2760 -
163.2761 -      [C] GROUP misc.test
163.2762 -      [S] 211 1234 3000234 3002322 misc.test
163.2763 -      [C] HEAD
163.2764 -      [S] 221 3000234 <45223423@example.com>
163.2765 -      [S] Path: pathost!demo!whitehouse!not-for-mail
163.2766 -      [S] From: "Demo User" <nobody@example.net>
163.2767 -      [S] Newsgroups: misc.test
163.2768 -      [S] Subject: I am just a test article
163.2769 -      [S] Date: 6 Oct 1998 04:38:40 -0500
163.2770 -      [S] Organization: An Example Net, Uncertain, Texas
163.2771 -      [S] Message-ID: <45223423@example.com>
163.2772 -      [S] .
163.2773 -
163.2774 -   Example of a successful retrieval of the headers of an article by
163.2775 -   message-id:
163.2776 -
163.2777 -      [C] HEAD <45223423@example.com>
163.2778 -      [S] 221 0 <45223423@example.com>
163.2779 -      [S] Path: pathost!demo!whitehouse!not-for-mail
163.2780 -      [S] From: "Demo User" <nobody@example.net>
163.2781 -      [S] Newsgroups: misc.test
163.2782 -      [S] Subject: I am just a test article
163.2783 -      [S] Date: 6 Oct 1998 04:38:40 -0500
163.2784 -      [S] Organization: An Example Net, Uncertain, Texas
163.2785 -      [S] Message-ID: <45223423@example.com>
163.2786 -      [S] .
163.2787 -
163.2788 -   Example of an unsuccessful retrieval of the headers of an article by
163.2789 -   message-id:
163.2790 -
163.2791 -      [C] HEAD <i.am.not.there@example.com>
163.2792 -      [S] 430 No Such Article Found
163.2793 -
163.2794 -
163.2795 -
163.2796 -
163.2797 -
163.2798 -
163.2799 -
163.2800 -Feather                     Standards Track                    [Page 50]
163.2801 -
163.2802 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2803 -
163.2804 -
163.2805 -   Example of an unsuccessful retrieval of the headers of an article by
163.2806 -   number:
163.2807 -
163.2808 -      [C] GROUP misc.test
163.2809 -      [S] 211 1234 3000234 3002322 misc.test
163.2810 -      [C] HEAD 300256
163.2811 -      [S] 423 No article with that number
163.2812 -
163.2813 -   Example of an unsuccessful retrieval of the headers of an article by
163.2814 -   number because no newsgroup was selected first:
163.2815 -
163.2816 -      [Assumes currently selected newsgroup is invalid.]
163.2817 -      [C] HEAD 300256
163.2818 -      [S] 412 No newsgroup selected
163.2819 -
163.2820 -   Example of an attempt to retrieve the headers of an article when the
163.2821 -   currently selected newsgroup is empty:
163.2822 -
163.2823 -      [C] GROUP example.empty.newsgroup
163.2824 -      [S] 211 0 0 0 example.empty.newsgroup
163.2825 -      [C] HEAD
163.2826 -      [S] 420 No current article selected
163.2827 -
163.2828 -6.2.3.  BODY
163.2829 -
163.2830 -6.2.3.1.  Usage
163.2831 -
163.2832 -   Indicating capability: READER
163.2833 -
163.2834 -   Syntax
163.2835 -     BODY message-id
163.2836 -     BODY number
163.2837 -     BODY
163.2838 -
163.2839 -   Responses
163.2840 -
163.2841 -   First form (message-id specified)
163.2842 -     222 0|n message-id    Body follows (multi-line)
163.2843 -     430                   No article with that message-id
163.2844 -
163.2845 -   Second form (article number specified)
163.2846 -     222 n message-id      Body follows (multi-line)
163.2847 -     412                   No newsgroup selected
163.2848 -     423                   No article with that number
163.2849 -
163.2850 -
163.2851 -
163.2852 -
163.2853 -
163.2854 -
163.2855 -
163.2856 -Feather                     Standards Track                    [Page 51]
163.2857 -
163.2858 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2859 -
163.2860 -
163.2861 -   Third form (current article number used)
163.2862 -     222 n message-id      Body follows (multi-line)
163.2863 -     412                   No newsgroup selected
163.2864 -     420                   Current article number is invalid
163.2865 -
163.2866 -   Parameters
163.2867 -     number        Requested article number
163.2868 -     n             Returned article number
163.2869 -     message-id    Article message-id
163.2870 -
163.2871 -6.2.3.2.  Description
163.2872 -
163.2873 -   The BODY command behaves identically to the ARTICLE command except
163.2874 -   that, if the article exists, the response code is 222 instead of 220
163.2875 -   and only the body is presented (the empty line separating the headers
163.2876 -   and body MUST NOT be included).
163.2877 -
163.2878 -6.2.3.3.  Examples
163.2879 -
163.2880 -   Example of a successful retrieval of the body of an article
163.2881 -   (explicitly not using an article number):
163.2882 -
163.2883 -      [C] GROUP misc.test
163.2884 -      [S] 211 1234 3000234 3002322 misc.test
163.2885 -      [C] BODY
163.2886 -      [S] 222 3000234 <45223423@example.com>
163.2887 -      [S] This is just a test article.
163.2888 -      [S] .
163.2889 -
163.2890 -   Example of a successful retrieval of the body of an article by
163.2891 -   message-id:
163.2892 -
163.2893 -      [C] BODY <45223423@example.com>
163.2894 -      [S] 222 0 <45223423@example.com>
163.2895 -      [S] This is just a test article.
163.2896 -      [S] .
163.2897 -
163.2898 -   Example of an unsuccessful retrieval of the body of an article by
163.2899 -   message-id:
163.2900 -
163.2901 -      [C] BODY <i.am.not.there@example.com>
163.2902 -      [S] 430 No Such Article Found
163.2903 -
163.2904 -
163.2905 -
163.2906 -
163.2907 -
163.2908 -
163.2909 -
163.2910 -
163.2911 -
163.2912 -Feather                     Standards Track                    [Page 52]
163.2913 -
163.2914 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2915 -
163.2916 -
163.2917 -   Example of an unsuccessful retrieval of the body of an article by
163.2918 -   number:
163.2919 -
163.2920 -      [C] GROUP misc.test
163.2921 -      [S] 211 1234 3000234 3002322 misc.test
163.2922 -      [C] BODY 300256
163.2923 -      [S] 423 No article with that number
163.2924 -
163.2925 -   Example of an unsuccessful retrieval of the body of an article by
163.2926 -   number because no newsgroup was selected first:
163.2927 -
163.2928 -      [Assumes currently selected newsgroup is invalid.]
163.2929 -      [C] BODY 300256
163.2930 -      [S] 412 No newsgroup selected
163.2931 -
163.2932 -   Example of an attempt to retrieve the body of an article when the
163.2933 -   currently selected newsgroup is empty:
163.2934 -
163.2935 -      [C] GROUP example.empty.newsgroup
163.2936 -      [S] 211 0 0 0 example.empty.newsgroup
163.2937 -      [C] BODY
163.2938 -      [S] 420 No current article selected
163.2939 -
163.2940 -6.2.4.  STAT
163.2941 -
163.2942 -6.2.4.1.  Usage
163.2943 -
163.2944 -   This command is mandatory.
163.2945 -
163.2946 -   Syntax
163.2947 -     STAT message-id
163.2948 -     STAT number
163.2949 -     STAT
163.2950 -
163.2951 -   Responses
163.2952 -
163.2953 -   First form (message-id specified)
163.2954 -     223 0|n message-id    Article exists
163.2955 -     430                   No article with that message-id
163.2956 -
163.2957 -   Second form (article number specified)
163.2958 -     223 n message-id      Article exists
163.2959 -     412                   No newsgroup selected
163.2960 -     423                   No article with that number
163.2961 -
163.2962 -
163.2963 -
163.2964 -
163.2965 -
163.2966 -
163.2967 -
163.2968 -Feather                     Standards Track                    [Page 53]
163.2969 -
163.2970 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.2971 -
163.2972 -
163.2973 -   Third form (current article number used)
163.2974 -     223 n message-id      Article exists
163.2975 -     412                   No newsgroup selected
163.2976 -     420                   Current article number is invalid
163.2977 -
163.2978 -   Parameters
163.2979 -     number        Requested article number
163.2980 -     n             Returned article number
163.2981 -     message-id    Article message-id
163.2982 -
163.2983 -6.2.4.2.  Description
163.2984 -
163.2985 -   The STAT command behaves identically to the ARTICLE command except
163.2986 -   that, if the article exists, it is NOT presented to the client and
163.2987 -   the response code is 223 instead of 220.  Note that the response is
163.2988 -   NOT multi-line.
163.2989 -
163.2990 -   This command allows the client to determine whether an article exists
163.2991 -   and, in the second and third forms, what its message-id is, without
163.2992 -   having to process an arbitrary amount of text.
163.2993 -
163.2994 -6.2.4.3.  Examples
163.2995 -
163.2996 -   Example of STAT on an existing article (explicitly not using an
163.2997 -   article number):
163.2998 -
163.2999 -      [C] GROUP misc.test
163.3000 -      [S] 211 1234 3000234 3002322 misc.test
163.3001 -      [C] STAT
163.3002 -      [S] 223 3000234 <45223423@example.com>
163.3003 -
163.3004 -   Example of STAT on an existing article by message-id:
163.3005 -
163.3006 -      [C] STAT <45223423@example.com>
163.3007 -      [S] 223 0 <45223423@example.com>
163.3008 -
163.3009 -   Example of STAT on an article not on the server by message-id:
163.3010 -
163.3011 -      [C] STAT <i.am.not.there@example.com>
163.3012 -      [S] 430 No Such Article Found
163.3013 -
163.3014 -   Example of STAT on an article not in the server by number:
163.3015 -
163.3016 -      [C] GROUP misc.test
163.3017 -      [S] 211 1234 3000234 3002322 misc.test
163.3018 -      [C] STAT 300256
163.3019 -      [S] 423 No article with that number
163.3020 -
163.3021 -
163.3022 -
163.3023 -
163.3024 -Feather                     Standards Track                    [Page 54]
163.3025 -
163.3026 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3027 -
163.3028 -
163.3029 -   Example of STAT on an article by number when no newsgroup was
163.3030 -   selected first:
163.3031 -
163.3032 -      [Assumes currently selected newsgroup is invalid.]
163.3033 -      [C] STAT 300256
163.3034 -      [S] 412 No newsgroup selected
163.3035 -
163.3036 -   Example of STAT on an article when the currently selected newsgroup
163.3037 -   is empty:
163.3038 -
163.3039 -      [C] GROUP example.empty.newsgroup
163.3040 -      [S] 211 0 0 0 example.empty.newsgroup
163.3041 -      [C] STAT
163.3042 -      [S] 420 No current article selected
163.3043 -
163.3044 -   Example of STAT by message-id on a server that sometimes reports the
163.3045 -   actual article number:
163.3046 -
163.3047 -      [C] GROUP misc.test
163.3048 -      [S] 211 1234 3000234 3002322 misc.test
163.3049 -      [C] STAT
163.3050 -      [S] 223 3000234 <45223423@example.com>
163.3051 -      [C] STAT <45223423@example.com>
163.3052 -      [S] 223 0 <45223423@example.com>
163.3053 -      [C] STAT <45223423@example.com>
163.3054 -      [S] 223 3000234 <45223423@example.com>
163.3055 -      [C] GROUP example.empty.newsgroup
163.3056 -      [S] 211 0 0 0 example.empty.newsgroup
163.3057 -      [C] STAT <45223423@example.com>
163.3058 -      [S] 223 0 <45223423@example.com>
163.3059 -      [C] GROUP alt.crossposts
163.3060 -      [S] 211 9999 111111 222222 alt.crossposts
163.3061 -      [C] STAT <45223423@example.com>
163.3062 -      [S] 223 123456 <45223423@example.com>
163.3063 -      [C] STAT
163.3064 -      [S] 223 111111 <23894720@example.com>
163.3065 -
163.3066 -   The first STAT command establishes the identity of an article in the
163.3067 -   group.  The second and third show that the server may, but need not,
163.3068 -   give the article number when the message-id is specified.  The fourth
163.3069 -   STAT command shows that zero must be specified if the article isn't
163.3070 -   in the currently selected newsgroup.  The fifth shows that the
163.3071 -   number, if provided, must be that relating to the currently selected
163.3072 -   newsgroup.  The last one shows that the current article number is
163.3073 -   still not changed by the use of STAT with a message-id even if it
163.3074 -   returns an article number.
163.3075 -
163.3076 -
163.3077 -
163.3078 -
163.3079 -
163.3080 -Feather                     Standards Track                    [Page 55]
163.3081 -
163.3082 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3083 -
163.3084 -
163.3085 -6.3.  Article Posting
163.3086 -
163.3087 -   Article posting is done in one of two ways: individual article
163.3088 -   posting from news-reading clients using POST, and article transfer
163.3089 -   from other news servers using IHAVE.
163.3090 -
163.3091 -6.3.1.  POST
163.3092 -
163.3093 -6.3.1.1.  Usage
163.3094 -
163.3095 -   Indicating capability: POST
163.3096 -
163.3097 -   This command MUST NOT be pipelined.
163.3098 -
163.3099 -   Syntax
163.3100 -     POST
163.3101 -
163.3102 -   Responses
163.3103 -
163.3104 -   Initial responses
163.3105 -     340    Send article to be posted
163.3106 -     440    Posting not permitted
163.3107 -
163.3108 -   Subsequent responses
163.3109 -     240    Article received OK
163.3110 -     441    Posting failed
163.3111 -
163.3112 -6.3.1.2.  Description
163.3113 -
163.3114 -   If posting is allowed, a 340 response MUST be returned to indicate
163.3115 -   that the article to be posted should be sent.  If posting is
163.3116 -   prohibited for some installation-dependent reason, a 440 response
163.3117 -   MUST be returned.
163.3118 -
163.3119 -   If posting is permitted, the article MUST be in the format specified
163.3120 -   in Section 3.6 and MUST be sent by the client to the server as a
163.3121 -   multi-line data block (see Section 3.1.1).  Thus a single dot (".")
163.3122 -   on a line indicates the end of the text, and lines starting with a
163.3123 -   dot in the original text have that dot doubled during transmission.
163.3124 -
163.3125 -   Following the presentation of the termination sequence by the client,
163.3126 -   the server MUST return a response indicating success or failure of
163.3127 -   the article transfer.  Note that response codes 340 and 440 are used
163.3128 -   in direct response to the POST command while 240 and 441 are returned
163.3129 -   after the article is sent.
163.3130 -
163.3131 -
163.3132 -
163.3133 -
163.3134 -
163.3135 -
163.3136 -Feather                     Standards Track                    [Page 56]
163.3137 -
163.3138 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3139 -
163.3140 -
163.3141 -   A response of 240 SHOULD indicate that, barring unforeseen server
163.3142 -   errors, the posted article will be made available on the server
163.3143 -   and/or transferred to other servers, as appropriate, possibly
163.3144 -   following further processing.  In other words, articles not wanted by
163.3145 -   the server SHOULD be rejected with a 441 response, rather than being
163.3146 -   accepted and then discarded silently.  However, the client SHOULD NOT
163.3147 -   assume that the article has been successfully transferred unless it
163.3148 -   receives an affirmative response from the server and SHOULD NOT
163.3149 -   assume that it is being made available to other clients without
163.3150 -   explicitly checking (for example, using the STAT command).
163.3151 -
163.3152 -   If the session is interrupted before the response is received, it is
163.3153 -   possible that an affirmative response was sent but has been lost.
163.3154 -   Therefore, in any subsequent session, the client SHOULD either check
163.3155 -   whether the article was successfully posted before resending or
163.3156 -   ensure that the server will allocate the same message-id to the new
163.3157 -   attempt (see Appendix A.2).  The latter approach is preferred since
163.3158 -   the article might not have been made available for reading yet (for
163.3159 -   example, it may have to go through a moderation process).
163.3160 -
163.3161 -6.3.1.3.  Examples
163.3162 -
163.3163 -   Example of a successful posting:
163.3164 -
163.3165 -      [C] POST
163.3166 -      [S] 340 Input article; end with <CR-LF>.<CR-LF>
163.3167 -      [C] From: "Demo User" <nobody@example.net>
163.3168 -      [C] Newsgroups: misc.test
163.3169 -      [C] Subject: I am just a test article
163.3170 -      [C] Organization: An Example Net
163.3171 -      [C]
163.3172 -      [C] This is just a test article.
163.3173 -      [C] .
163.3174 -      [S] 240 Article received OK
163.3175 -
163.3176 -   Example of an unsuccessful posting:
163.3177 -
163.3178 -      [C] POST
163.3179 -      [S] 340 Input article; end with <CR-LF>.<CR-LF>
163.3180 -      [C] From: "Demo User" <nobody@example.net>
163.3181 -      [C] Newsgroups: misc.test
163.3182 -      [C] Subject: I am just a test article
163.3183 -      [C] Organization: An Example Net
163.3184 -      [C]
163.3185 -      [C] This is just a test article.
163.3186 -      [C] .
163.3187 -      [S] 441 Posting failed
163.3188 -
163.3189 -
163.3190 -
163.3191 -
163.3192 -Feather                     Standards Track                    [Page 57]
163.3193 -
163.3194 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3195 -
163.3196 -
163.3197 -   Example of an attempt to post when posting is not allowed:
163.3198 -
163.3199 -      [Initial connection set-up completed.]
163.3200 -      [S] 201 NNTP Service Ready, posting prohibited
163.3201 -      [C] POST
163.3202 -      [S] 440 Posting not permitted
163.3203 -
163.3204 -6.3.2.  IHAVE
163.3205 -
163.3206 -6.3.2.1.  Usage
163.3207 -
163.3208 -   Indicating capability: IHAVE
163.3209 -
163.3210 -   This command MUST NOT be pipelined.
163.3211 -
163.3212 -   Syntax
163.3213 -     IHAVE message-id
163.3214 -
163.3215 -   Responses
163.3216 -
163.3217 -   Initial responses
163.3218 -     335    Send article to be transferred
163.3219 -     435    Article not wanted
163.3220 -     436    Transfer not possible; try again later
163.3221 -
163.3222 -   Subsequent responses
163.3223 -     235    Article transferred OK
163.3224 -     436    Transfer failed; try again later
163.3225 -     437    Transfer rejected; do not retry
163.3226 -
163.3227 -   Parameters
163.3228 -     message-id    Article message-id
163.3229 -
163.3230 -6.3.2.2.  Description
163.3231 -
163.3232 -   The IHAVE command informs the server that the client has an article
163.3233 -   with the specified message-id.  If the server desires a copy of that
163.3234 -   article, a 335 response MUST be returned, instructing the client to
163.3235 -   send the entire article.  If the server does not want the article
163.3236 -   (if, for example, the server already has a copy of it), a 435
163.3237 -   response MUST be returned, indicating that the article is not wanted.
163.3238 -   Finally, if the article isn't wanted immediately but the client
163.3239 -   should retry later if possible (if, for example, another client is in
163.3240 -   the process of sending the same article to the server), a 436
163.3241 -   response MUST be returned.
163.3242 -
163.3243 -
163.3244 -
163.3245 -
163.3246 -
163.3247 -
163.3248 -Feather                     Standards Track                    [Page 58]
163.3249 -
163.3250 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3251 -
163.3252 -
163.3253 -   If transmission of the article is requested, the client MUST send the
163.3254 -   entire article, including headers and body, to the server as a
163.3255 -   multi-line data block (see Section 3.1.1).  Thus, a single dot (".")
163.3256 -   on a line indicates the end of the text, and lines starting with a
163.3257 -   dot in the original text have that dot doubled during transmission.
163.3258 -   The server MUST return a 235 response, indicating that the article
163.3259 -   was successfully transferred; a 436 response, indicating that the
163.3260 -   transfer failed but should be tried again later; or a 437 response,
163.3261 -   indicating that the article was rejected.
163.3262 -
163.3263 -   This function differs from the POST command in that it is intended
163.3264 -   for use in transferring already-posted articles between hosts.  It
163.3265 -   SHOULD NOT be used when the client is a personal news-reading
163.3266 -   program, since use of this command indicates that the article has
163.3267 -   already been posted at another site and is simply being forwarded
163.3268 -   from another host.  However, despite this, the server MAY elect not
163.3269 -   to post or forward the article if, after further examination of the
163.3270 -   article, it deems it inappropriate to do so.  Reasons for such
163.3271 -   subsequent rejection of an article may include problems such as
163.3272 -   inappropriate newsgroups or distributions, disc space limitations,
163.3273 -   article lengths, garbled headers, and the like.  These are typically
163.3274 -   restrictions enforced by the server host's news software and not
163.3275 -   necessarily by the NNTP server itself.
163.3276 -
163.3277 -   The client SHOULD NOT assume that the article has been successfully
163.3278 -   transferred unless it receives an affirmative response from the
163.3279 -   server.  A lack of response (such as a dropped network connection or
163.3280 -   a network timeout) SHOULD be treated the same as a 436 response.
163.3281 -
163.3282 -   Because some news server software may not immediately be able to
163.3283 -   determine whether an article is suitable for posting or forwarding,
163.3284 -   an NNTP server MAY acknowledge the successful transfer of the article
163.3285 -   (with a 235 response) but later silently discard it.
163.3286 -
163.3287 -
163.3288 -
163.3289 -
163.3290 -
163.3291 -
163.3292 -
163.3293 -
163.3294 -
163.3295 -
163.3296 -
163.3297 -
163.3298 -
163.3299 -
163.3300 -
163.3301 -
163.3302 -
163.3303 -
163.3304 -Feather                     Standards Track                    [Page 59]
163.3305 -
163.3306 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3307 -
163.3308 -
163.3309 -6.3.2.3.  Examples
163.3310 -
163.3311 -   Example of successfully sending an article to another site:
163.3312 -
163.3313 -      [C] IHAVE <i.am.an.article.you.will.want@example.com>
163.3314 -      [S] 335 Send it; end with <CR-LF>.<CR-LF>
163.3315 -      [C] Path: pathost!demo!somewhere!not-for-mail
163.3316 -      [C] From: "Demo User" <nobody@example.com>
163.3317 -      [C] Newsgroups: misc.test
163.3318 -      [C] Subject: I am just a test article
163.3319 -      [C] Date: 6 Oct 1998 04:38:40 -0500
163.3320 -      [C] Organization: An Example Com, San Jose, CA
163.3321 -      [C] Message-ID: <i.am.an.article.you.will.want@example.com>
163.3322 -      [C]
163.3323 -      [C] This is just a test article.
163.3324 -      [C] .
163.3325 -      [S] 235 Article transferred OK
163.3326 -
163.3327 -   Example of sending an article to another site that rejects it.  Note
163.3328 -   that the message-id in the IHAVE command is not the same as the one
163.3329 -   in the article headers; while this is bad practice and SHOULD NOT be
163.3330 -   done, it is not forbidden.
163.3331 -
163.3332 -      [C] IHAVE <i.am.an.article.you.will.want@example.com>
163.3333 -      [S] 335 Send it; end with <CR-LF>.<CR-LF>
163.3334 -      [C] Path: pathost!demo!somewhere!not-for-mail
163.3335 -      [C] From: "Demo User" <nobody@example.com>
163.3336 -      [C] Newsgroups: misc.test
163.3337 -      [C] Subject: I am just a test article
163.3338 -      [C] Date: 6 Oct 1998 04:38:40 -0500
163.3339 -      [C] Organization: An Example Com, San Jose, CA
163.3340 -      [C] Message-ID: <i.am.an.article.you.have@example.com>
163.3341 -      [C]
163.3342 -      [C] This is just a test article.
163.3343 -      [C] .
163.3344 -      [S] 437 Article rejected; don't send again
163.3345 -
163.3346 -
163.3347 -
163.3348 -
163.3349 -
163.3350 -
163.3351 -
163.3352 -
163.3353 -
163.3354 -
163.3355 -
163.3356 -
163.3357 -
163.3358 -
163.3359 -
163.3360 -Feather                     Standards Track                    [Page 60]
163.3361 -
163.3362 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3363 -
163.3364 -
163.3365 -   Example of sending an article to another site where the transfer
163.3366 -   fails:
163.3367 -
163.3368 -      [C] IHAVE <i.am.an.article.you.will.want@example.com>
163.3369 -      [S] 335 Send it; end with <CR-LF>.<CR-LF>
163.3370 -      [C] Path: pathost!demo!somewhere!not-for-mail
163.3371 -      [C] From: "Demo User" <nobody@example.com>
163.3372 -      [C] Newsgroups: misc.test
163.3373 -      [C] Subject: I am just a test article
163.3374 -      [C] Date: 6 Oct 1998 04:38:40 -0500
163.3375 -      [C] Organization: An Example Com, San Jose, CA
163.3376 -      [C] Message-ID: <i.am.an.article.you.will.want@example.com>
163.3377 -      [C]
163.3378 -      [C] This is just a test article.
163.3379 -      [C] .
163.3380 -      [S] 436 Transfer failed
163.3381 -
163.3382 -   Example of sending an article to a site that already has it:
163.3383 -
163.3384 -      [C] IHAVE <i.am.an.article.you.have@example.com>
163.3385 -      [S] 435 Duplicate
163.3386 -
163.3387 -   Example of sending an article to a site that requests that the
163.3388 -   article be tried again later:
163.3389 -
163.3390 -      [C] IHAVE <i.am.an.article.you.defer@example.com>
163.3391 -      [S] 436 Retry later
163.3392 -
163.3393 -7.  Information Commands
163.3394 -
163.3395 -   This section lists other commands that may be used at any time
163.3396 -   between the beginning of a session and its termination.  Using these
163.3397 -   commands does not alter any state information, but the response
163.3398 -   generated from their use may provide useful information to clients.
163.3399 -
163.3400 -7.1.  DATE
163.3401 -
163.3402 -7.1.1.  Usage
163.3403 -
163.3404 -   Indicating capability: READER
163.3405 -
163.3406 -   Syntax
163.3407 -     DATE
163.3408 -
163.3409 -   Responses
163.3410 -     111 yyyymmddhhmmss    Server date and time
163.3411 -
163.3412 -
163.3413 -
163.3414 -
163.3415 -
163.3416 -Feather                     Standards Track                    [Page 61]
163.3417 -
163.3418 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3419 -
163.3420 -
163.3421 -   Parameters
163.3422 -     yyyymmddhhmmss    Current UTC date and time on server
163.3423 -
163.3424 -7.1.2.  Description
163.3425 -
163.3426 -   This command exists to help clients find out the current Coordinated
163.3427 -   Universal Time [TF.686-1] from the server's perspective.  This
163.3428 -   command SHOULD NOT be used as a substitute for NTP [RFC1305] but to
163.3429 -   provide information that might be useful when using the NEWNEWS
163.3430 -   command (see Section 7.4).
163.3431 -
163.3432 -   The DATE command MUST return a timestamp from the same clock as is
163.3433 -   used for determining article arrival and group creation times (see
163.3434 -   Section 6).  This clock SHOULD be monotonic, and adjustments SHOULD
163.3435 -   be made by running it fast or slow compared to "real" time rather
163.3436 -   than by making sudden jumps.  A system providing NNTP service SHOULD
163.3437 -   keep the system clock as accurate as possible, either with NTP or by
163.3438 -   some other method.
163.3439 -
163.3440 -   The server MUST return a 111 response specifying the date and time on
163.3441 -   the server in the form yyyymmddhhmmss.  This date and time is in
163.3442 -   Coordinated Universal Time.
163.3443 -
163.3444 -7.1.3.  Examples
163.3445 -
163.3446 -      [C] DATE
163.3447 -      [S] 111 19990623135624
163.3448 -
163.3449 -7.2.  HELP
163.3450 -
163.3451 -7.2.1.  Usage
163.3452 -
163.3453 -   This command is mandatory.
163.3454 -
163.3455 -   Syntax
163.3456 -     HELP
163.3457 -
163.3458 -   Responses
163.3459 -     100    Help text follows (multi-line)
163.3460 -
163.3461 -7.2.2.  Description
163.3462 -
163.3463 -   This command provides a short summary of the commands that are
163.3464 -   understood by this implementation of the server.  The help text will
163.3465 -   be presented as a multi-line data block following the 100 response
163.3466 -   code.
163.3467 -
163.3468 -
163.3469 -
163.3470 -
163.3471 -
163.3472 -Feather                     Standards Track                    [Page 62]
163.3473 -
163.3474 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3475 -
163.3476 -
163.3477 -   This text is not guaranteed to be in any particular format (but must
163.3478 -   be UTF-8) and MUST NOT be used by clients as a replacement for the
163.3479 -   CAPABILITIES command described in Section 5.2.
163.3480 -
163.3481 -7.2.3.  Examples
163.3482 -
163.3483 -      [C] HELP
163.3484 -      [S] 100 Help text follows
163.3485 -      [S] This is some help text.  There is no specific
163.3486 -      [S] formatting requirement for this test, though
163.3487 -      [S] it is customary for it to list the valid commands
163.3488 -      [S] and give a brief definition of what they do.
163.3489 -      [S] .
163.3490 -
163.3491 -7.3.  NEWGROUPS
163.3492 -
163.3493 -7.3.1.  Usage
163.3494 -
163.3495 -   Indicating capability: READER
163.3496 -
163.3497 -   Syntax
163.3498 -     NEWGROUPS date time [GMT]
163.3499 -
163.3500 -   Responses
163.3501 -     231    List of new newsgroups follows (multi-line)
163.3502 -
163.3503 -   Parameters
163.3504 -     date    Date in yymmdd or yyyymmdd format
163.3505 -     time    Time in hhmmss format
163.3506 -
163.3507 -7.3.2.  Description
163.3508 -
163.3509 -   This command returns a list of newsgroups created on the server since
163.3510 -   the specified date and time.  The results are in the same format as
163.3511 -   the LIST ACTIVE command (see Section 7.6.3).  However, they MAY
163.3512 -   include groups not available on the server (and so not returned by
163.3513 -   LIST ACTIVE) and MAY omit groups for which the creation date is not
163.3514 -   available.
163.3515 -
163.3516 -   The date is specified as 6 or 8 digits in the format [xx]yymmdd,
163.3517 -   where xx is the first two digits of the year (19-99), yy is the last
163.3518 -   two digits of the year (00-99), mm is the month (01-12), and dd is
163.3519 -   the day of the month (01-31).  Clients SHOULD specify all four digits
163.3520 -   of the year.  If the first two digits of the year are not specified
163.3521 -   (this is supported only for backward compatibility), the year is to
163.3522 -   be taken from the current century if yy is smaller than or equal to
163.3523 -   the current year, and the previous century otherwise.
163.3524 -
163.3525 -
163.3526 -
163.3527 -
163.3528 -Feather                     Standards Track                    [Page 63]
163.3529 -
163.3530 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3531 -
163.3532 -
163.3533 -   The time is specified as 6 digits in the format hhmmss, where hh is
163.3534 -   the hours in the 24-hour clock (00-23), mm is the minutes (00-59),
163.3535 -   and ss is the seconds (00-60, to allow for leap seconds).  The token
163.3536 -   "GMT" specifies that the date and time are given in Coordinated
163.3537 -   Universal Time [TF.686-1]; if it is omitted, then the date and time
163.3538 -   are specified in the server's local timezone.  Note that there is no
163.3539 -   way of using the protocol specified in this document to establish the
163.3540 -   server's local timezone.
163.3541 -
163.3542 -   Note that an empty list is a possible valid response and indicates
163.3543 -   that there are no new newsgroups since that date-time.
163.3544 -
163.3545 -   Clients SHOULD make all queries using Coordinated Universal Time
163.3546 -   (i.e., by including the "GMT" argument) when possible.
163.3547 -
163.3548 -7.3.3.  Examples
163.3549 -
163.3550 -   Example where there are new groups:
163.3551 -
163.3552 -      [C] NEWGROUPS 19990624 000000 GMT
163.3553 -      [S] 231 list of new newsgroups follows
163.3554 -      [S] alt.rfc-writers.recovery 4 1 y
163.3555 -      [S] tx.natives.recovery 89 56 y
163.3556 -      [S] .
163.3557 -
163.3558 -   Example where there are no new groups:
163.3559 -
163.3560 -      [C] NEWGROUPS 19990624 000000 GMT
163.3561 -      [S] 231 list of new newsgroups follows
163.3562 -      [S] .
163.3563 -
163.3564 -7.4.  NEWNEWS
163.3565 -
163.3566 -7.4.1.  Usage
163.3567 -
163.3568 -   Indicating capability: NEWNEWS
163.3569 -
163.3570 -   Syntax
163.3571 -     NEWNEWS wildmat date time [GMT]
163.3572 -
163.3573 -   Responses
163.3574 -     230    List of new articles follows (multi-line)
163.3575 -
163.3576 -   Parameters
163.3577 -     wildmat    Newsgroups of interest
163.3578 -     date       Date in yymmdd or yyyymmdd format
163.3579 -     time       Time in hhmmss format
163.3580 -
163.3581 -
163.3582 -
163.3583 -
163.3584 -Feather                     Standards Track                    [Page 64]
163.3585 -
163.3586 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3587 -
163.3588 -
163.3589 -7.4.2.  Description
163.3590 -
163.3591 -   This command returns a list of message-ids of articles posted or
163.3592 -   received on the server, in the newsgroups whose names match the
163.3593 -   wildmat, since the specified date and time.  One message-id is sent
163.3594 -   on each line; the order of the response has no specific significance
163.3595 -   and may vary from response to response in the same session.  A
163.3596 -   message-id MAY appear more than once; if it does, it has the same
163.3597 -   meaning as if it appeared only once.
163.3598 -
163.3599 -   Date and time are in the same format as the NEWGROUPS command (see
163.3600 -   Section 7.3).
163.3601 -
163.3602 -   Note that an empty list is a possible valid response and indicates
163.3603 -   that there is currently no new news in the relevant groups.
163.3604 -
163.3605 -   Clients SHOULD make all queries in Coordinated Universal Time (i.e.,
163.3606 -   by using the "GMT" argument) when possible.
163.3607 -
163.3608 -7.4.3.  Examples
163.3609 -
163.3610 -   Example where there are new articles:
163.3611 -
163.3612 -      [C] NEWNEWS news.*,sci.* 19990624 000000 GMT
163.3613 -      [S] 230 list of new articles by message-id follows
163.3614 -      [S] <i.am.a.new.article@example.com>
163.3615 -      [S] <i.am.another.new.article@example.com>
163.3616 -      [S] .
163.3617 -
163.3618 -   Example where there are no new articles:
163.3619 -
163.3620 -      [C] NEWNEWS alt.* 19990624 000000 GMT
163.3621 -      [S] 230 list of new articles by message-id follows
163.3622 -      [S] .
163.3623 -
163.3624 -7.5.  Time
163.3625 -
163.3626 -   As described in Section 6, each article has an arrival timestamp.
163.3627 -   Each newsgroup also has a creation timestamp.  These timestamps are
163.3628 -   used by the NEWNEWS and NEWGROUP commands to construct their
163.3629 -   responses.
163.3630 -
163.3631 -   Clients can ensure that they do not have gaps in lists of articles or
163.3632 -   groups by using the DATE command in the following manner:
163.3633 -
163.3634 -   First session:
163.3635 -      Issue DATE command and record result.
163.3636 -      Issue NEWNEWS command using a previously chosen timestamp.
163.3637 -
163.3638 -
163.3639 -
163.3640 -Feather                     Standards Track                    [Page 65]
163.3641 -
163.3642 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3643 -
163.3644 -
163.3645 -   Subsequent sessions:
163.3646 -      Issue DATE command and hold result in temporary storage.
163.3647 -      Issue NEWNEWS command using timestamp saved from previous session.
163.3648 -      Overwrite saved timestamp with that currently in temporary
163.3649 -      storage.
163.3650 -
163.3651 -   In order to allow for minor errors, clients MAY want to adjust the
163.3652 -   timestamp back by two or three minutes before using it in NEWNEWS.
163.3653 -
163.3654 -7.5.1.  Examples
163.3655 -
163.3656 -   First session:
163.3657 -
163.3658 -      [C] DATE
163.3659 -      [S] 111 20010203112233
163.3660 -      [C] NEWNEWS local.chat 20001231 235959 GMT
163.3661 -      [S] 230 list follows
163.3662 -      [S] <article.1@local.service>
163.3663 -      [S] <article.2@local.service>
163.3664 -      [S] <article.3@local.service>
163.3665 -      [S] .
163.3666 -
163.3667 -   Second session (the client has subtracted 3 minutes from the
163.3668 -   timestamp returned previously):
163.3669 -
163.3670 -      [C] DATE
163.3671 -      [S] 111 20010204003344
163.3672 -      [C] NEWNEWS local.chat 20010203 111933 GMT
163.3673 -      [S] 230 list follows
163.3674 -      [S] <article.3@local.service>
163.3675 -      [S] <article.4@local.service>
163.3676 -      [S] <article.5@local.service>
163.3677 -      [S] .
163.3678 -
163.3679 -   Note how <article.3@local.service> arrived in the 3 minute gap and so
163.3680 -   is listed in both responses.
163.3681 -
163.3682 -7.6.  The LIST Commands
163.3683 -
163.3684 -   The LIST family of commands all return information that is multi-line
163.3685 -   and that can, in general, be expected not to change during the
163.3686 -   session.  Often the information is related to newsgroups, in which
163.3687 -   case the response has one line per newsgroup and a wildmat MAY be
163.3688 -   provided to restrict the groups for which information is returned.
163.3689 -
163.3690 -   The set of available keywords (including those provided by
163.3691 -   extensions) is given in the capability list with capability label
163.3692 -   LIST.
163.3693 -
163.3694 -
163.3695 -
163.3696 -Feather                     Standards Track                    [Page 66]
163.3697 -
163.3698 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3699 -
163.3700 -
163.3701 -7.6.1.  LIST
163.3702 -
163.3703 -7.6.1.1.  Usage
163.3704 -
163.3705 -   Indicating capability: LIST
163.3706 -
163.3707 -   Syntax
163.3708 -     LIST [keyword [wildmat|argument]]
163.3709 -
163.3710 -   Responses
163.3711 -     215    Information follows (multi-line)
163.3712 -
163.3713 -   Parameters
163.3714 -     keyword     Information requested [1]
163.3715 -     argument    Specific to keyword
163.3716 -     wildmat     Groups of interest
163.3717 -
163.3718 -   [1] If no keyword is provided, it defaults to ACTIVE.
163.3719 -
163.3720 -7.6.1.2.  Description
163.3721 -
163.3722 -   The LIST command allows the server to provide blocks of information
163.3723 -   to the client.  This information may be global or may be related to
163.3724 -   newsgroups; in the latter case, the information may be returned
163.3725 -   either for all groups or only for those matching a wildmat.  Each
163.3726 -   block of information is represented by a different keyword.  The
163.3727 -   command returns the specific information identified by the keyword.
163.3728 -
163.3729 -   If the information is available, it is returned as a multi-line data
163.3730 -   block following the 215 response code.  The format of the information
163.3731 -   depends on the keyword.  The information MAY be affected by the
163.3732 -   additional argument, but the format MUST NOT be.
163.3733 -
163.3734 -   If the information is based on newsgroups and the optional wildmat
163.3735 -   argument is specified, the response is limited to only the groups (if
163.3736 -   any) whose names match the wildmat and for which the information is
163.3737 -   available.
163.3738 -
163.3739 -   Note that an empty list is a possible valid response; for a
163.3740 -   newsgroup-based keyword, it indicates that there are no groups
163.3741 -   meeting the above criteria.
163.3742 -
163.3743 -   If the keyword is not recognised, or if an argument is specified and
163.3744 -   the keyword does not expect one, a 501 response code MUST BE
163.3745 -   returned.  If the keyword is recognised but the server does not
163.3746 -   maintain the information, a 503 response code MUST BE returned.
163.3747 -
163.3748 -
163.3749 -
163.3750 -
163.3751 -
163.3752 -Feather                     Standards Track                    [Page 67]
163.3753 -
163.3754 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3755 -
163.3756 -
163.3757 -   The LIST command MUST NOT change the visible state of the server in
163.3758 -   any way; that is, the behaviour of subsequent commands MUST NOT be
163.3759 -   affected by whether the LIST command was issued.  For example, it
163.3760 -   MUST NOT make groups available that otherwise would not have been.
163.3761 -
163.3762 -7.6.1.3.  Examples
163.3763 -
163.3764 -   Example of LIST with the ACTIVE keyword:
163.3765 -
163.3766 -      [C] LIST ACTIVE
163.3767 -      [S] 215 list of newsgroups follows
163.3768 -      [S] misc.test 3002322 3000234 y
163.3769 -      [S] comp.risks 442001 441099 m
163.3770 -      [S] alt.rfc-writers.recovery 4 1 y
163.3771 -      [S] tx.natives.recovery 89 56 y
163.3772 -      [S] tx.natives.recovery.d 11 9 n
163.3773 -      [S] .
163.3774 -
163.3775 -   Example of LIST with no keyword:
163.3776 -
163.3777 -      [C] LIST
163.3778 -      [S] 215 list of newsgroups follows
163.3779 -      [S] misc.test 3002322 3000234 y
163.3780 -      [S] comp.risks 442001 441099 m
163.3781 -      [S] alt.rfc-writers.recovery 4 1 y
163.3782 -      [S] tx.natives.recovery 89 56 y
163.3783 -      [S] tx.natives.recovery.d 11 9 n
163.3784 -      [S] .
163.3785 -
163.3786 -   The output is identical to that of the previous example.
163.3787 -
163.3788 -   Example of LIST on a newsgroup-based keyword with and without
163.3789 -   wildmat:
163.3790 -
163.3791 -      [C] LIST ACTIVE.TIMES
163.3792 -      [S] 215 information follows
163.3793 -      [S] misc.test 930445408 <creatme@isc.org>
163.3794 -      [S] alt.rfc-writers.recovery 930562309 <m@example.com>
163.3795 -      [S] tx.natives.recovery 930678923 <sob@academ.com>
163.3796 -      [S] .
163.3797 -      [C] LIST ACTIVE.TIMES tx.*
163.3798 -      [S] 215 information follows
163.3799 -      [S] tx.natives.recovery 930678923 <sob@academ.com>
163.3800 -      [S] .
163.3801 -
163.3802 -
163.3803 -
163.3804 -
163.3805 -
163.3806 -
163.3807 -
163.3808 -Feather                     Standards Track                    [Page 68]
163.3809 -
163.3810 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3811 -
163.3812 -
163.3813 -   Example of LIST returning an error where the keyword is recognized
163.3814 -   but the software does not maintain this information:
163.3815 -
163.3816 -      [C] CAPABILITIES
163.3817 -      [S] 101 Capability list:
163.3818 -      [S] VERSION 2
163.3819 -      [S] READER
163.3820 -      [S] LIST ACTIVE NEWSGROUPS ACTIVE.TIMES XTRA.DATA
163.3821 -      [S] .
163.3822 -      [C] LIST XTRA.DATA
163.3823 -      [S] 503 Data item not stored
163.3824 -
163.3825 -   Example of LIST where the keyword is not recognised:
163.3826 -
163.3827 -      [C] CAPABILITIES
163.3828 -      [S] 101 Capability list:
163.3829 -      [S] VERSION 2
163.3830 -      [S] READER
163.3831 -      [S] LIST ACTIVE NEWSGROUPS ACTIVE.TIMES XTRA.DATA
163.3832 -      [S] .
163.3833 -      [C] LIST DISTRIB.PATS
163.3834 -      [S] 501 Syntax Error
163.3835 -
163.3836 -7.6.2.  Standard LIST Keywords
163.3837 -
163.3838 -   This specification defines the following LIST keywords:
163.3839 -
163.3840 -   +--------------+---------------+------------------------------------+
163.3841 -   | Keyword      | Definition    | Status                             |
163.3842 -   +--------------+---------------+------------------------------------+
163.3843 -   | ACTIVE       | Section 7.6.3 | Mandatory if the READER capability |
163.3844 -   |              |               | is advertised                      |
163.3845 -   |              |               |                                    |
163.3846 -   | ACTIVE.TIMES | Section 7.6.4 | Optional                           |
163.3847 -   |              |               |                                    |
163.3848 -   | DISTRIB.PATS | Section 7.6.5 | Optional                           |
163.3849 -   |              |               |                                    |
163.3850 -   | HEADERS      | Section 8.6   | Mandatory if the HDR capability is |
163.3851 -   |              |               | advertised                         |
163.3852 -   |              |               |                                    |
163.3853 -   | NEWSGROUPS   | Section 7.6.6 | Mandatory if the READER capability |
163.3854 -   |              |               | is advertised                      |
163.3855 -   |              |               |                                    |
163.3856 -   | OVERVIEW.FMT | Section 8.4   | Mandatory if the OVER capability   |
163.3857 -   |              |               | is advertised                      |
163.3858 -   +--------------+---------------+------------------------------------+
163.3859 -
163.3860 -
163.3861 -
163.3862 -
163.3863 -
163.3864 -Feather                     Standards Track                    [Page 69]
163.3865 -
163.3866 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3867 -
163.3868 -
163.3869 -   Where one of these LIST keywords is supported by a server, it MUST
163.3870 -   have the meaning given in the relevant sub-section.
163.3871 -
163.3872 -7.6.3.  LIST ACTIVE
163.3873 -
163.3874 -   This keyword MUST be supported by servers advertising the READER
163.3875 -   capability.
163.3876 -
163.3877 -   LIST ACTIVE returns a list of valid newsgroups and associated
163.3878 -   information.  If no wildmat is specified, the server MUST include
163.3879 -   every group that the client is permitted to select with the GROUP
163.3880 -   command (Section 6.1.1).  Each line of this list consists of four
163.3881 -   fields separated from each other by one or more spaces:
163.3882 -
163.3883 -   o  The name of the newsgroup.
163.3884 -   o  The reported high water mark for the group.
163.3885 -   o  The reported low water mark for the group.
163.3886 -   o  The current status of the group on this server.
163.3887 -
163.3888 -   The reported high and low water marks are as described in the GROUP
163.3889 -   command (see Section 6.1.1), but note that they are in the opposite
163.3890 -   order to the 211 response to that command.
163.3891 -
163.3892 -   The status field is typically one of the following:
163.3893 -
163.3894 -   "y" Posting is permitted.
163.3895 -
163.3896 -   "n" Posting is not permitted.
163.3897 -
163.3898 -   "m" Postings will be forwarded to the newsgroup moderator.
163.3899 -
163.3900 -   The server SHOULD use these values when these meanings are required
163.3901 -   and MUST NOT use them with any other meaning.  Other values for the
163.3902 -   status may exist; the definition of these other values and the
163.3903 -   circumstances under which they are returned may be specified in an
163.3904 -   extension or may be private to the server.  A client SHOULD treat an
163.3905 -   unrecognized status as giving no information.
163.3906 -
163.3907 -   The status of a newsgroup only indicates how posts to that newsgroup
163.3908 -   are normally processed and is not necessarily customised to the
163.3909 -   specific client.  For example, if the current client is forbidden
163.3910 -   from posting, then this will apply equally to groups with status "y".
163.3911 -   Conversely, a client with special privileges (not defined by this
163.3912 -   specification) might be able to post to a group with status "n".
163.3913 -
163.3914 -
163.3915 -
163.3916 -
163.3917 -
163.3918 -
163.3919 -
163.3920 -Feather                     Standards Track                    [Page 70]
163.3921 -
163.3922 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3923 -
163.3924 -
163.3925 -   For example:
163.3926 -
163.3927 -      [C] LIST ACTIVE
163.3928 -      [S] 215 list of newsgroups follows
163.3929 -      [S] misc.test 3002322 3000234 y
163.3930 -      [S] comp.risks 442001 441099 m
163.3931 -      [S] alt.rfc-writers.recovery 4 1 y
163.3932 -      [S] tx.natives.recovery 89 56 y
163.3933 -      [S] tx.natives.recovery.d 11 9 n
163.3934 -      [S] .
163.3935 -
163.3936 -   or, on an implementation that includes leading zeroes:
163.3937 -
163.3938 -      [C] LIST ACTIVE
163.3939 -      [S] 215 list of newsgroups follows
163.3940 -      [S] misc.test 0003002322 0003000234 y
163.3941 -      [S] comp.risks 0000442001 0000441099 m
163.3942 -      [S] alt.rfc-writers.recovery 0000000004 0000000001 y
163.3943 -      [S] tx.natives.recovery 0000000089 0000000056 y
163.3944 -      [S] tx.natives.recovery.d 0000000011 0000000009 n
163.3945 -      [S] .
163.3946 -
163.3947 -   The information is newsgroup based, and a wildmat MAY be specified,
163.3948 -   in which case the response is limited to only the groups (if any)
163.3949 -   whose names match the wildmat.  For example:
163.3950 -
163.3951 -      [C] LIST ACTIVE *.recovery
163.3952 -      [S] 215 list of newsgroups follows
163.3953 -      [S] alt.rfc-writers.recovery 4 1 y
163.3954 -      [S] tx.natives.recovery 89 56 y
163.3955 -      [S] .
163.3956 -
163.3957 -7.6.4.  LIST ACTIVE.TIMES
163.3958 -
163.3959 -   This keyword is optional.
163.3960 -
163.3961 -   The active.times list is maintained by some NNTP servers to contain
163.3962 -   information about who created a particular newsgroup and when.  Each
163.3963 -   line of this list consists of three fields separated from each other
163.3964 -   by one or more spaces.  The first field is the name of the newsgroup.
163.3965 -   The second is the time when this group was created on this news
163.3966 -   server, measured in seconds since the start of January 1, 1970.  The
163.3967 -   third is plain text intended to describe the entity that created the
163.3968 -   newsgroup; it is often a mailbox as defined in RFC 2822 [RFC2822].
163.3969 -   For example:
163.3970 -
163.3971 -
163.3972 -
163.3973 -
163.3974 -
163.3975 -
163.3976 -Feather                     Standards Track                    [Page 71]
163.3977 -
163.3978 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.3979 -
163.3980 -
163.3981 -      [C] LIST ACTIVE.TIMES
163.3982 -      [S] 215 information follows
163.3983 -      [S] misc.test 930445408 <creatme@isc.org>
163.3984 -      [S] alt.rfc-writers.recovery 930562309 <m@example.com>
163.3985 -      [S] tx.natives.recovery 930678923 <sob@academ.com>
163.3986 -      [S] .
163.3987 -
163.3988 -   The list MAY omit newsgroups for which the information is unavailable
163.3989 -   and MAY include groups not available on the server; in particular, it
163.3990 -   MAY omit all groups created before the date and time of the oldest
163.3991 -   entry.  The client MUST NOT assume that the list is complete or that
163.3992 -   it matches the list returned by the LIST ACTIVE command
163.3993 -   (Section 7.6.3).  The NEWGROUPS command (Section 7.3) may provide a
163.3994 -   better way to access this information, and the results of the two
163.3995 -   commands SHOULD be consistent except that, if the latter is invoked
163.3996 -   with a date and time earlier than the oldest entry in active.times
163.3997 -   list, its result may include extra groups.
163.3998 -
163.3999 -   The information is newsgroup based, and a wildmat MAY be specified,
163.4000 -   in which case the response is limited to only the groups (if any)
163.4001 -   whose names match the wildmat.
163.4002 -
163.4003 -7.6.5.  LIST DISTRIB.PATS
163.4004 -
163.4005 -   This keyword is optional.
163.4006 -
163.4007 -   The distrib.pats list is maintained by some NNTP servers to assist
163.4008 -   clients to choose a value for the content of the Distribution header
163.4009 -   of a news article being posted.  Each line of this list consists of
163.4010 -   three fields separated from each other by a colon (":").  The first
163.4011 -   field is a weight, the second field is a wildmat (which may be a
163.4012 -   simple newsgroup name), and the third field is a value for the
163.4013 -   Distribution header content.  For example:
163.4014 -
163.4015 -      [C] LIST DISTRIB.PATS
163.4016 -      [S] 215 information follows
163.4017 -      [S] 10:local.*:local
163.4018 -      [S] 5:*:world
163.4019 -      [S] 20:local.here.*:thissite
163.4020 -      [S] .
163.4021 -
163.4022 -   The client MAY use this information to construct an appropriate
163.4023 -   Distribution header given the name of a newsgroup.  To do so, it
163.4024 -   should determine the lines whose second field matches the newsgroup
163.4025 -   name, select from among them the line with the highest weight (with 0
163.4026 -   being the lowest), and use the value of the third field to construct
163.4027 -   the Distribution header.
163.4028 -
163.4029 -
163.4030 -
163.4031 -
163.4032 -Feather                     Standards Track                    [Page 72]
163.4033 -
163.4034 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4035 -
163.4036 -
163.4037 -   The information is not newsgroup based, and an argument MUST NOT be
163.4038 -   specified.
163.4039 -
163.4040 -7.6.6.  LIST NEWSGROUPS
163.4041 -
163.4042 -   This keyword MUST be supported by servers advertising the READER
163.4043 -   capability.
163.4044 -
163.4045 -   The newsgroups list is maintained by NNTP servers to contain the name
163.4046 -   of each newsgroup that is available on the server and a short
163.4047 -   description about the purpose of the group.  Each line of this list
163.4048 -   consists of two fields separated from each other by one or more space
163.4049 -   or TAB characters (the usual practice is a single TAB).  The first
163.4050 -   field is the name of the newsgroup, and the second is a short
163.4051 -   description of the group.  For example:
163.4052 -
163.4053 -      [C] LIST NEWSGROUPS
163.4054 -      [S] 215 information follows
163.4055 -      [S] misc.test General Usenet testing
163.4056 -      [S] alt.rfc-writers.recovery RFC Writers Recovery
163.4057 -      [S] tx.natives.recovery Texas Natives Recovery
163.4058 -      [S] .
163.4059 -
163.4060 -   The list MAY omit newsgroups for which the information is unavailable
163.4061 -   and MAY include groups not available on the server.  The client MUST
163.4062 -   NOT assume that the list is complete or that it matches the list
163.4063 -   returned by LIST ACTIVE.
163.4064 -
163.4065 -   The description SHOULD be in UTF-8.  However, servers often obtain
163.4066 -   the information from external sources.  These sources may have used
163.4067 -   different encodings (ones that use octets in the range 128 to 255 in
163.4068 -   some other manner) and, in that case, the server MAY pass it on
163.4069 -   unchanged.  Therefore, clients MUST be prepared to receive such
163.4070 -   descriptions.
163.4071 -
163.4072 -   The information is newsgroup based, and a wildmat MAY be specified,
163.4073 -   in which case the response is limited to only the groups (if any)
163.4074 -   whose names match the wildmat.
163.4075 -
163.4076 -8.  Article Field Access Commands
163.4077 -
163.4078 -   This section lists commands that may be used to access specific
163.4079 -   article fields; that is, headers of articles and metadata about
163.4080 -   articles.  These commands typically fetch data from an "overview
163.4081 -   database", which is a database of headers extracted from incoming
163.4082 -   articles plus metadata determined as the article arrives.  Only
163.4083 -   certain fields are included in the database.
163.4084 -
163.4085 -
163.4086 -
163.4087 -
163.4088 -Feather                     Standards Track                    [Page 73]
163.4089 -
163.4090 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4091 -
163.4092 -
163.4093 -   This section is based on the Overview/NOV database [ROBE1995]
163.4094 -   developed by Geoff Collyer.
163.4095 -
163.4096 -8.1.  Article Metadata
163.4097 -
163.4098 -   Article "metadata" is data about articles that does not occur within
163.4099 -   the article itself.  Each metadata item has a name that MUST begin
163.4100 -   with a colon (and that MUST NOT contain a colon elsewhere within it).
163.4101 -   As with header names, metadata item names are not case sensitive.
163.4102 -
163.4103 -   When generating a metadata item, the server MUST compute it for
163.4104 -   itself and MUST NOT trust any related value provided in the article.
163.4105 -   (In particular, a Lines or Bytes header in the article MUST NOT be
163.4106 -   assumed to specify the correct number of lines or bytes in the
163.4107 -   article.)  If the server has access to several non-identical copies
163.4108 -   of an article, the value returned MUST be correct for any copy of
163.4109 -   that article retrieved during the same session.
163.4110 -
163.4111 -   This specification defines two metadata items: ":bytes" and ":lines".
163.4112 -   Other metadata items may be defined by extensions.  The names of
163.4113 -   metadata items defined by registered extensions MUST NOT begin with
163.4114 -   ":x-".  To avoid the risk of a clash with a future registered
163.4115 -   extension, the names of metadata items defined by private extensions
163.4116 -   SHOULD begin with ":x-".
163.4117 -
163.4118 -8.1.1.  The :bytes Metadata Item
163.4119 -
163.4120 -   The :bytes metadata item for an article is a decimal integer.  It
163.4121 -   SHOULD equal the number of octets in the entire article: headers,
163.4122 -   body, and separating empty line (counting a CRLF pair as two octets,
163.4123 -   and excluding both the "." CRLF terminating the response and any "."
163.4124 -   added for "dot-stuffing" purposes).
163.4125 -
163.4126 -   Note to client implementers: some existing servers return a value
163.4127 -   different from that above.  The commonest reasons for this are as
163.4128 -   follows:
163.4129 -
163.4130 -   o  Counting a CRLF pair as one octet.
163.4131 -
163.4132 -   o  Including the "." character used for dot-stuffing in the number.
163.4133 -
163.4134 -   o  Including the terminating "." CRLF in the number.
163.4135 -
163.4136 -   o  Using one copy of an article for counting the octets but then
163.4137 -      returning another one that differs in some (permitted) manner.
163.4138 -
163.4139 -   Implementations should be prepared for such variation and MUST NOT
163.4140 -   rely on the value being accurate.
163.4141 -
163.4142 -
163.4143 -
163.4144 -Feather                     Standards Track                    [Page 74]
163.4145 -
163.4146 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4147 -
163.4148 -
163.4149 -8.1.2.  The :lines Metadata Item
163.4150 -
163.4151 -   The :lines metadata item for an article is a decimal integer.  It
163.4152 -   MUST equal the number of lines in the article body (excluding the
163.4153 -   empty line separating headers and body).  Equivalently, it is two
163.4154 -   less than the number of CRLF pairs that the BODY command would return
163.4155 -   for that article (the extra two are those following the response code
163.4156 -   and the termination octet).
163.4157 -
163.4158 -8.2.  Database Consistency
163.4159 -
163.4160 -   The information stored in the overview database may change over time.
163.4161 -   If the database records the content or absence of a given field (that
163.4162 -   is, a header or metadata item) for all articles, it is said to be
163.4163 -   "consistent" for that field.  If it records the content of a header
163.4164 -   for some articles but not for others that nevertheless included that
163.4165 -   header, or if it records a metadata item for some articles but not
163.4166 -   for others to which that item applies, it is said to be
163.4167 -   "inconsistent" for that field.
163.4168 -
163.4169 -   The LIST OVERVIEW.FMT command SHOULD list all the fields for which
163.4170 -   the database is consistent at that moment.  It MAY omit such fields
163.4171 -   (for example, if it is not known whether the database is consistent
163.4172 -   or inconsistent).  It MUST NOT include fields for which the database
163.4173 -   is inconsistent or that are not stored in the database.  Therefore,
163.4174 -   if a header appears in the LIST OVERVIEW.FMT output but not in the
163.4175 -   OVER output for a given article, that header does not appear in the
163.4176 -   article (similarly for metadata items).
163.4177 -
163.4178 -   These rules assume that the fields being stored in the database
163.4179 -   remain constant for long periods of time, and therefore the database
163.4180 -   will be consistent.  When the set of fields to be stored is changed,
163.4181 -   it will be inconsistent until either the database is rebuilt or the
163.4182 -   only articles remaining are those received since the change.
163.4183 -   Therefore, the output from LIST OVERVIEW.FMT needs to be altered
163.4184 -   twice.  Firstly, before any fields stop being stored they MUST be
163.4185 -   removed from the output; then, when the database is once more known
163.4186 -   to be consistent, the new fields SHOULD be added to the output.
163.4187 -
163.4188 -   If the HDR command uses the overview database rather than taking
163.4189 -   information directly from the articles, the same issues of
163.4190 -   consistency and inconsistency apply, and the LIST HEADERS command
163.4191 -   SHOULD take the same approach as the LIST OVERVIEW.FMT command in
163.4192 -   resolving them.
163.4193 -
163.4194 -
163.4195 -
163.4196 -
163.4197 -
163.4198 -
163.4199 -
163.4200 -Feather                     Standards Track                    [Page 75]
163.4201 -
163.4202 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4203 -
163.4204 -
163.4205 -8.3.  OVER
163.4206 -
163.4207 -8.3.1.  Usage
163.4208 -
163.4209 -   Indicating capability: OVER
163.4210 -
163.4211 -   Syntax
163.4212 -     OVER message-id
163.4213 -     OVER range
163.4214 -     OVER
163.4215 -
163.4216 -   Responses
163.4217 -
163.4218 -   First form (message-id specified)
163.4219 -     224    Overview information follows (multi-line)
163.4220 -     430    No article with that message-id
163.4221 -
163.4222 -   Second form (range specified)
163.4223 -     224    Overview information follows (multi-line)
163.4224 -     412    No newsgroup selected
163.4225 -     423    No articles in that range
163.4226 -
163.4227 -   Third form (current article number used)
163.4228 -     224    Overview information follows (multi-line)
163.4229 -     412    No newsgroup selected
163.4230 -     420    Current article number is invalid
163.4231 -
163.4232 -   Parameters
163.4233 -     range         Number(s) of articles
163.4234 -     message-id    Message-id of article
163.4235 -
163.4236 -8.3.2.  Description
163.4237 -
163.4238 -   The OVER command returns the contents of all the fields in the
163.4239 -   database for an article specified by message-id, or from a specified
163.4240 -   article or range of articles in the currently selected newsgroup.
163.4241 -
163.4242 -   The message-id argument indicates a specific article.  The range
163.4243 -   argument may be any of the following:
163.4244 -
163.4245 -   o  An article number.
163.4246 -
163.4247 -   o  An article number followed by a dash to indicate all following.
163.4248 -
163.4249 -   o  An article number followed by a dash followed by another article
163.4250 -      number.
163.4251 -
163.4252 -   If neither is specified, the current article number is used.
163.4253 -
163.4254 -
163.4255 -
163.4256 -Feather                     Standards Track                    [Page 76]
163.4257 -
163.4258 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4259 -
163.4260 -
163.4261 -   Support for the first (message-id) form is optional.  If it is
163.4262 -   supported, the OVER capability line MUST include the argument
163.4263 -   "MSGID".  Otherwise, the capability line MUST NOT include this
163.4264 -   argument, and the OVER command MUST return the generic response code
163.4265 -   503 when this form is used.
163.4266 -
163.4267 -   If the information is available, it is returned as a multi-line data
163.4268 -   block following the 224 response code and contains one line per
163.4269 -   article, sorted in numerical order of article number.  (Note that
163.4270 -   unless the argument is a range including a dash, there will be
163.4271 -   exactly one line in the data block.)  Each line consists of a number
163.4272 -   of fields separated by a TAB.  A field may be empty (in which case
163.4273 -   there will be two adjacent TABs), and a sequence of trailing TABs may
163.4274 -   be omitted.
163.4275 -
163.4276 -   The first 8 fields MUST be the following, in order:
163.4277 -
163.4278 -      "0" or article number (see below)
163.4279 -      Subject header content
163.4280 -      From header content
163.4281 -      Date header content
163.4282 -      Message-ID header content
163.4283 -      References header content
163.4284 -      :bytes metadata item
163.4285 -      :lines metadata item
163.4286 -
163.4287 -   If the article is specified by message-id (the first form of the
163.4288 -   command), the article number MUST be replaced with zero, except that
163.4289 -   if there is a currently selected newsgroup and the article is present
163.4290 -   in that group, the server MAY use the article's number in that group.
163.4291 -   (See the ARTICLE command (Section 6.2.1) and STAT examples
163.4292 -   (Section 6.2.4.3) for more details.)  In the other two forms of the
163.4293 -   command, the article number MUST be returned.
163.4294 -
163.4295 -   Any subsequent fields are the contents of the other headers and
163.4296 -   metadata held in the database.
163.4297 -
163.4298 -   For the five mandatory headers, the content of each field MUST be
163.4299 -   based on the content of the header (that is, with the header name and
163.4300 -   following colon and space removed).  If the article does not contain
163.4301 -   that header, or if the content is empty, the field MUST be empty.
163.4302 -   For the two mandatory metadata items, the content of the field MUST
163.4303 -   be just the value, with no other text.
163.4304 -
163.4305 -   For all subsequent fields that contain headers, the content MUST be
163.4306 -   the entire header line other than the trailing CRLF.  For all
163.4307 -   subsequent fields that contain metadata, the field consists of the
163.4308 -   metadata name, a single space, and then the value.
163.4309 -
163.4310 -
163.4311 -
163.4312 -Feather                     Standards Track                    [Page 77]
163.4313 -
163.4314 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4315 -
163.4316 -
163.4317 -   For all fields, the value is processed by first removing all CRLF
163.4318 -   pairs (that is, undoing any folding and removing the terminating
163.4319 -   CRLF) and then replacing each TAB with a single space.  If there is
163.4320 -   no such header in the article, no such metadata item, or no header or
163.4321 -   item stored in the database for that article, the corresponding field
163.4322 -   MUST be empty.
163.4323 -
163.4324 -   Note that, after unfolding, the characters NUL, LF, and CR cannot
163.4325 -   occur in the header of an article offered by a conformant server.
163.4326 -   Nevertheless, servers SHOULD check for these characters and replace
163.4327 -   each one by a single space (so that, for example, CR LF LF TAB will
163.4328 -   become two spaces, since the CR and first LF will be removed by the
163.4329 -   unfolding process).  This will encourage robustness in the face of
163.4330 -   non-conforming data; it is also possible that future versions of this
163.4331 -   specification could permit these characters to appear in articles.
163.4332 -
163.4333 -   The server SHOULD NOT produce output for articles that no longer
163.4334 -   exist.
163.4335 -
163.4336 -   If the argument is a message-id and no such article exists, a 430
163.4337 -   response MUST be returned.  If the argument is a range or is omitted
163.4338 -   and the currently selected newsgroup is invalid, a 412 response MUST
163.4339 -   be returned.  If the argument is a range and no articles in that
163.4340 -   number range exist in the currently selected newsgroup, including the
163.4341 -   case where the second number is less than the first one, a 423
163.4342 -   response MUST be returned.  If the argument is omitted and the
163.4343 -   current article number is invalid, a 420 response MUST be returned.
163.4344 -
163.4345 -8.3.3.  Examples
163.4346 -
163.4347 -   In the first four examples, TAB has been replaced by vertical bar and
163.4348 -   some lines have been folded for readability.
163.4349 -
163.4350 -   Example of a successful retrieval of overview information for an
163.4351 -   article (explicitly not using an article number):
163.4352 -
163.4353 -      [C] GROUP misc.test
163.4354 -      [S] 211 1234 3000234 3002322 misc.test
163.4355 -      [C] OVER
163.4356 -      [S] 224 Overview information follows
163.4357 -      [S] 3000234|I am just a test article|"Demo User"
163.4358 -          <nobody@example.com>|6 Oct 1998 04:38:40 -0500|
163.4359 -          <45223423@example.com>|<45454@example.net>|1234|
163.4360 -          17|Xref: news.example.com misc.test:3000363
163.4361 -      [S] .
163.4362 -
163.4363 -
163.4364 -
163.4365 -
163.4366 -
163.4367 -
163.4368 -Feather                     Standards Track                    [Page 78]
163.4369 -
163.4370 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4371 -
163.4372 -
163.4373 -   Example of a successful retrieval of overview information for an
163.4374 -   article by message-id:
163.4375 -
163.4376 -      [C] CAPABILITIES
163.4377 -      [S] 101 Capability list:
163.4378 -      [S] VERSION 2
163.4379 -      [S] READER
163.4380 -      [S] OVER MSGID
163.4381 -      [S] LIST ACTIVE NEWSGROUPS OVERVIEW.FMT
163.4382 -      [S] .
163.4383 -      [C] OVER <45223423@example.com>
163.4384 -      [S] 224 Overview information follows
163.4385 -      [S] 0|I am just a test article|"Demo User"
163.4386 -          <nobody@example.com>|6 Oct 1998 04:38:40 -0500|
163.4387 -          <45223423@example.com>|<45454@example.net>|1234|
163.4388 -          17|Xref: news.example.com misc.test:3000363
163.4389 -      [S] .
163.4390 -
163.4391 -   Note that the article number has been replaced by "0".
163.4392 -
163.4393 -   Example of the same commands on a system that does not implement
163.4394 -   retrieval by message-id:
163.4395 -
163.4396 -      [C] CAPABILITIES
163.4397 -      [S] 101 Capability list:
163.4398 -      [S] VERSION 2
163.4399 -      [S] READER
163.4400 -      [S] OVER
163.4401 -      [S] LIST ACTIVE NEWSGROUPS OVERVIEW.FMT
163.4402 -      [S] .
163.4403 -      [C] OVER <45223423@example.com>
163.4404 -      [S] 503 Overview by message-id unsupported
163.4405 -
163.4406 -
163.4407 -
163.4408 -
163.4409 -
163.4410 -
163.4411 -
163.4412 -
163.4413 -
163.4414 -
163.4415 -
163.4416 -
163.4417 -
163.4418 -
163.4419 -
163.4420 -
163.4421 -
163.4422 -
163.4423 -
163.4424 -Feather                     Standards Track                    [Page 79]
163.4425 -
163.4426 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4427 -
163.4428 -
163.4429 -   Example of a successful retrieval of overview information for a range
163.4430 -   of articles:
163.4431 -
163.4432 -      [C] GROUP misc.test
163.4433 -      [S] 211 1234 3000234 3002322 misc.test
163.4434 -      [C] OVER 3000234-3000240
163.4435 -      [S] 224 Overview information follows
163.4436 -      [S] 3000234|I am just a test article|"Demo User"
163.4437 -          <nobody@example.com>|6 Oct 1998 04:38:40 -0500|
163.4438 -          <45223423@example.com>|<45454@example.net>|1234|
163.4439 -          17|Xref: news.example.com misc.test:3000363
163.4440 -      [S] 3000235|Another test article|nobody@nowhere.to
163.4441 -          (Demo User)|6 Oct 1998 04:38:45 -0500|<45223425@to.to>||
163.4442 -          4818|37||Distribution: fi
163.4443 -      [S] 3000238|Re: I am just a test article|somebody@elsewhere.to|
163.4444 -          7 Oct 1998 11:38:40 +1200|<kfwer3v@elsewhere.to>|
163.4445 -          <45223423@to.to>|9234|51
163.4446 -      [S] .
163.4447 -
163.4448 -   Note the missing "References" and Xref headers in the second line,
163.4449 -   the missing trailing fields in the first and last lines, and that
163.4450 -   there are only results for those articles that still exist.
163.4451 -
163.4452 -   Example of an unsuccessful retrieval of overview information on an
163.4453 -   article by number:
163.4454 -
163.4455 -      [C] GROUP misc.test
163.4456 -      [S] 211 1234 3000234 3002322 misc.test
163.4457 -      [C] OVER 300256
163.4458 -      [S] 423 No such article in this group
163.4459 -
163.4460 -   Example of an invalid range:
163.4461 -
163.4462 -      [C] GROUP misc.test
163.4463 -      [S] 211 1234 3000234 3002322 misc.test
163.4464 -      [C] OVER 3000444-3000222
163.4465 -      [S] 423 Empty range
163.4466 -
163.4467 -   Example of an unsuccessful retrieval of overview information by
163.4468 -   number because no newsgroup was selected first:
163.4469 -
163.4470 -      [Assumes currently selected newsgroup is invalid.]
163.4471 -      [C] OVER
163.4472 -      [S] 412 No newsgroup selected
163.4473 -
163.4474 -
163.4475 -
163.4476 -
163.4477 -
163.4478 -
163.4479 -
163.4480 -Feather                     Standards Track                    [Page 80]
163.4481 -
163.4482 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4483 -
163.4484 -
163.4485 -   Example of an attempt to retrieve information when the currently
163.4486 -   selected newsgroup is empty:
163.4487 -
163.4488 -      [C] GROUP example.empty.newsgroup
163.4489 -      [S] 211 0 0 0 example.empty.newsgroup
163.4490 -      [C] OVER
163.4491 -      [S] 420 No current article selected
163.4492 -
163.4493 -8.4.  LIST OVERVIEW.FMT
163.4494 -
163.4495 -8.4.1.  Usage
163.4496 -
163.4497 -   Indicating capability: OVER
163.4498 -
163.4499 -   Syntax
163.4500 -     LIST OVERVIEW.FMT
163.4501 -
163.4502 -   Responses
163.4503 -     215    Information follows (multi-line)
163.4504 -
163.4505 -8.4.2.  Description
163.4506 -
163.4507 -   See Section 7.6.1 for general requirements of the LIST command.
163.4508 -
163.4509 -   The LIST OVERVIEW.FMT command returns a description of the fields in
163.4510 -   the database for which it is consistent (as described above).  The
163.4511 -   information is returned as a multi-line data block following the 215
163.4512 -   response code.  The information contains one line per field in the
163.4513 -   order in which they are returned by the OVER command; the first 7
163.4514 -   lines MUST (except for the case of letters) be exactly as follows:
163.4515 -
163.4516 -       Subject:
163.4517 -       From:
163.4518 -       Date:
163.4519 -       Message-ID:
163.4520 -       References:
163.4521 -       :bytes
163.4522 -       :lines
163.4523 -
163.4524 -   For compatibility with existing implementations, the last two lines
163.4525 -   MAY instead be:
163.4526 -
163.4527 -       Bytes:
163.4528 -       Lines:
163.4529 -
163.4530 -   even though they refer to metadata, not headers.
163.4531 -
163.4532 -
163.4533 -
163.4534 -
163.4535 -
163.4536 -Feather                     Standards Track                    [Page 81]
163.4537 -
163.4538 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4539 -
163.4540 -
163.4541 -   All subsequent lines MUST consist of either a header name followed by
163.4542 -   ":full", or the name of a piece of metadata.
163.4543 -
163.4544 -   There are no leading or trailing spaces in the output.
163.4545 -
163.4546 -   Note that the 7 fixed lines describe the 2nd to 8th fields of the
163.4547 -   OVER output.  The "full" suffix (which may use either uppercase,
163.4548 -   lowercase, or a mix) is a reminder that the corresponding fields
163.4549 -   include the header name.
163.4550 -
163.4551 -   This command MAY generate different results if it is used more than
163.4552 -   once in a session.
163.4553 -
163.4554 -   If the OVER command is not implemented, the meaning of the output
163.4555 -   from this command is not specified, but it must still meet the above
163.4556 -   syntactic requirements.
163.4557 -
163.4558 -8.4.3.  Examples
163.4559 -
163.4560 -   Example of LIST OVERVIEW.FMT output corresponding to the example OVER
163.4561 -   output above, in the preferred format:
163.4562 -
163.4563 -      [C] LIST OVERVIEW.FMT
163.4564 -      [S] 215 Order of fields in overview database.
163.4565 -      [S] Subject:
163.4566 -      [S] From:
163.4567 -      [S] Date:
163.4568 -      [S] Message-ID:
163.4569 -      [S] References:
163.4570 -      [S] :bytes
163.4571 -      [S] :lines
163.4572 -      [S] Xref:full
163.4573 -      [S] Distribution:full
163.4574 -      [S] .
163.4575 -
163.4576 -
163.4577 -
163.4578 -
163.4579 -
163.4580 -
163.4581 -
163.4582 -
163.4583 -
163.4584 -
163.4585 -
163.4586 -
163.4587 -
163.4588 -
163.4589 -
163.4590 -
163.4591 -
163.4592 -Feather                     Standards Track                    [Page 82]
163.4593 -
163.4594 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4595 -
163.4596 -
163.4597 -   Example of LIST OVERVIEW.FMT output corresponding to the example OVER
163.4598 -   output above, in the alternative format:
163.4599 -
163.4600 -      [C] LIST OVERVIEW.FMT
163.4601 -      [S] 215 Order of fields in overview database.
163.4602 -      [S] Subject:
163.4603 -      [S] From:
163.4604 -      [S] Date:
163.4605 -      [S] Message-ID:
163.4606 -      [S] References:
163.4607 -      [S] Bytes:
163.4608 -      [S] Lines:
163.4609 -      [S] Xref:FULL
163.4610 -      [S] Distribution:FULL
163.4611 -      [S] .
163.4612 -
163.4613 -8.5.  HDR
163.4614 -
163.4615 -8.5.1.  Usage
163.4616 -
163.4617 -   Indicating capability: HDR
163.4618 -
163.4619 -   Syntax
163.4620 -     HDR field message-id
163.4621 -     HDR field range
163.4622 -     HDR field
163.4623 -
163.4624 -   Responses
163.4625 -
163.4626 -   First form (message-id specified)
163.4627 -     225    Headers follow (multi-line)
163.4628 -     430    No article with that message-id
163.4629 -
163.4630 -   Second form (range specified)
163.4631 -     225    Headers follow (multi-line)
163.4632 -     412    No newsgroup selected
163.4633 -     423    No articles in that range
163.4634 -
163.4635 -   Third form (current article number used)
163.4636 -     225    Headers follow (multi-line)
163.4637 -     412    No newsgroup selected
163.4638 -     420    Current article number is invalid
163.4639 -
163.4640 -   Parameters
163.4641 -     field         Name of field
163.4642 -     range         Number(s) of articles
163.4643 -     message-id    Message-id of article
163.4644 -
163.4645 -
163.4646 -
163.4647 -
163.4648 -Feather                     Standards Track                    [Page 83]
163.4649 -
163.4650 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4651 -
163.4652 -
163.4653 -8.5.2.  Description
163.4654 -
163.4655 -   The HDR command provides access to specific fields from an article
163.4656 -   specified by message-id, or from a specified article or range of
163.4657 -   articles in the currently selected newsgroup.  It MAY take the
163.4658 -   information directly from the articles or from the overview database.
163.4659 -   In the case of headers, an implementation MAY restrict the use of
163.4660 -   this command to a specific list of headers or MAY allow it to be used
163.4661 -   with any header; it may behave differently when it is used with a
163.4662 -   message-id argument and when it is used with a range or no argument.
163.4663 -
163.4664 -   The required field argument is the name of a header with the colon
163.4665 -   omitted (e.g., "subject") or the name of a metadata item including
163.4666 -   the leading colon (e.g., ":bytes"), and is case insensitive.
163.4667 -
163.4668 -   The message-id argument indicates a specific article.  The range
163.4669 -   argument may be any of the following:
163.4670 -
163.4671 -   o  An article number.
163.4672 -
163.4673 -   o  An article number followed by a dash to indicate all following.
163.4674 -
163.4675 -   o  An article number followed by a dash followed by another article
163.4676 -      number.
163.4677 -
163.4678 -   If neither is specified, the current article number is used.
163.4679 -
163.4680 -   If the information is available, it is returned as a multi-line data
163.4681 -   block following the 225 response code and contains one line for each
163.4682 -   article in the range that exists.  (Note that unless the argument is
163.4683 -   a range including a dash, there will be exactly one line in the data
163.4684 -   block.)  The line consists of the article number, a space, and then
163.4685 -   the contents of the field.  In the case of a header, the header name,
163.4686 -   the colon, and the first space after the colon are all omitted.
163.4687 -
163.4688 -   If the article is specified by message-id (the first form of the
163.4689 -   command), the article number MUST be replaced with zero, except that
163.4690 -   if there is a currently selected newsgroup and the article is present
163.4691 -   in that group, the server MAY use the article's number in that group.
163.4692 -   (See the ARTICLE command (Section 6.2.1) and STAT examples
163.4693 -   (Section 6.2.4.3) for more details.)  In the other two forms of the
163.4694 -   command, the article number MUST be returned.
163.4695 -
163.4696 -   Header contents are modified as follows: all CRLF pairs are removed,
163.4697 -   and then each TAB is replaced with a single space.  (Note that this
163.4698 -   is the same transformation as is performed by the OVER command
163.4699 -   (Section 8.3.2), and the same comment concerning NUL, CR, and LF
163.4700 -   applies.)
163.4701 -
163.4702 -
163.4703 -
163.4704 -Feather                     Standards Track                    [Page 84]
163.4705 -
163.4706 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4707 -
163.4708 -
163.4709 -   Note the distinction between headers and metadata appearing to have
163.4710 -   the same meaning.  Headers are always taken unchanged from the
163.4711 -   article; metadata are always calculated.  For example, a request for
163.4712 -   "Lines" returns the contents of the "Lines" header of the specified
163.4713 -   articles, if any, no matter whether they accurately state the number
163.4714 -   of lines, while a request for ":lines" returns the line count
163.4715 -   metadata, which is always the actual number of lines irrespective of
163.4716 -   what any header may state.
163.4717 -
163.4718 -   If the requested header is not present in the article, or if it is
163.4719 -   present but empty, a line for that article is included in the output,
163.4720 -   but the header content portion of the line is empty (the space after
163.4721 -   the article number MAY be retained or omitted).  If the header occurs
163.4722 -   in a given article more than once, only the content of the first
163.4723 -   occurrence is returned by HDR.  If any article number in the provided
163.4724 -   range does not exist in the group, no line for that article number is
163.4725 -   included in the output.
163.4726 -
163.4727 -   If the second argument is a message-id and no such article exists, a
163.4728 -   430 response MUST be returned.  If the second argument is a range or
163.4729 -   is omitted and the currently selected newsgroup is invalid, a 412
163.4730 -   response MUST be returned.  If the second argument is a range and no
163.4731 -   articles in that number range exist in the currently selected
163.4732 -   newsgroup, including the case where the second number is less than
163.4733 -   the first one, a 423 response MUST be returned.  If the second
163.4734 -   argument is omitted and the current article number is invalid, a 420
163.4735 -   response MUST be returned.
163.4736 -
163.4737 -   A server MAY only allow HDR commands for a limited set of fields; it
163.4738 -   may behave differently in this respect for the first (message-id)
163.4739 -   form from how it would for the other forms.  If so, it MUST respond
163.4740 -   with the generic 503 response to attempts to request other fields,
163.4741 -   rather than return erroneous results, such as a successful empty
163.4742 -   response.
163.4743 -
163.4744 -   If HDR uses the overview database and it is inconsistent for the
163.4745 -   requested field, the server MAY return what results it can, or it MAY
163.4746 -   respond with the generic 503 response.  In the latter case, the field
163.4747 -   MUST NOT appear in the output from LIST HEADERS.
163.4748 -
163.4749 -
163.4750 -
163.4751 -
163.4752 -
163.4753 -
163.4754 -
163.4755 -
163.4756 -
163.4757 -
163.4758 -
163.4759 -
163.4760 -Feather                     Standards Track                    [Page 85]
163.4761 -
163.4762 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4763 -
163.4764 -
163.4765 -8.5.3.  Examples
163.4766 -
163.4767 -   Example of a successful retrieval of subject lines from a range of
163.4768 -   articles (3000235 has no Subject header, and 3000236 is missing):
163.4769 -
163.4770 -      [C] GROUP misc.test
163.4771 -      [S] 211 1234 3000234 3002322 misc.test
163.4772 -      [C] HDR Subject 3000234-3000238
163.4773 -      [S] 225 Headers follow
163.4774 -      [S] 3000234 I am just a test article
163.4775 -      [S] 3000235
163.4776 -      [S] 3000237 Re: I am just a test article
163.4777 -      [S] 3000238 Ditto
163.4778 -      [S] .
163.4779 -
163.4780 -   Example of a successful retrieval of line counts from a range of
163.4781 -   articles:
163.4782 -
163.4783 -      [C] GROUP misc.test
163.4784 -      [S] 211 1234 3000234 3002322 misc.test
163.4785 -      [C] HDR :lines 3000234-3000238
163.4786 -      [S] 225 Headers follow
163.4787 -      [S] 3000234 42
163.4788 -      [S] 3000235 5
163.4789 -      [S] 3000237 11
163.4790 -      [S] 3000238 2378
163.4791 -      [S] .
163.4792 -
163.4793 -   Example of a successful retrieval of the subject line from an article
163.4794 -   by message-id:
163.4795 -
163.4796 -      [C] GROUP misc.test
163.4797 -      [S] 211 1234 3000234 3002322 misc.test
163.4798 -      [C] HDR subject <i.am.a.test.article@example.com>
163.4799 -      [S] 225 Header information follows
163.4800 -      [S] 0 I am just a test article
163.4801 -      [S] .
163.4802 -
163.4803 -   Example of a successful retrieval of the subject line from the
163.4804 -   current article:
163.4805 -
163.4806 -      [C] GROUP misc.test
163.4807 -      [S] 211 1234 3000234 3002322 misc.test
163.4808 -      [C] HDR subject
163.4809 -      [S] 225 Header information follows
163.4810 -      [S] 3000234 I am just a test article
163.4811 -      [S] .
163.4812 -
163.4813 -
163.4814 -
163.4815 -
163.4816 -Feather                     Standards Track                    [Page 86]
163.4817 -
163.4818 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4819 -
163.4820 -
163.4821 -   Example of an unsuccessful retrieval of a header from an article by
163.4822 -   message-id:
163.4823 -
163.4824 -      [C] HDR subject <i.am.not.there@example.com>
163.4825 -      [S] 430 No Such Article Found
163.4826 -
163.4827 -   Example of an unsuccessful retrieval of headers from articles by
163.4828 -   number because no newsgroup was selected first:
163.4829 -
163.4830 -      [Assumes currently selected newsgroup is invalid.]
163.4831 -      [C] HDR subject 300256-
163.4832 -      [S] 412 No newsgroup selected
163.4833 -
163.4834 -   Example of an unsuccessful retrieval of headers because the currently
163.4835 -   selected newsgroup is empty:
163.4836 -
163.4837 -      [C] GROUP example.empty.newsgroup
163.4838 -      [S] 211 0 0 0 example.empty.newsgroup
163.4839 -      [C] HDR subject 1-
163.4840 -      [S] 423 No articles in that range
163.4841 -
163.4842 -   Example of an unsuccessful retrieval of headers because the server
163.4843 -   does not allow HDR commands for that header:
163.4844 -
163.4845 -      [C] GROUP misc.test
163.4846 -      [S] 211 1234 3000234 3002322 misc.test
163.4847 -      [C] HDR Content-Type 3000234-3000238
163.4848 -      [S] 503 HDR not permitted on Content-Type
163.4849 -
163.4850 -8.6.  LIST HEADERS
163.4851 -
163.4852 -8.6.1.  Usage
163.4853 -
163.4854 -   Indicating capability: HDR
163.4855 -
163.4856 -   Syntax
163.4857 -     LIST HEADERS [MSGID|RANGE]
163.4858 -
163.4859 -   Responses
163.4860 -     215    Field list follows (multi-line)
163.4861 -
163.4862 -   Parameters
163.4863 -     MSGID    Requests list for access by message-id
163.4864 -     RANGE    Requests list for access by range
163.4865 -
163.4866 -
163.4867 -
163.4868 -
163.4869 -
163.4870 -
163.4871 -
163.4872 -Feather                     Standards Track                    [Page 87]
163.4873 -
163.4874 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4875 -
163.4876 -
163.4877 -8.6.2.  Description
163.4878 -
163.4879 -   See Section 7.6.1 for general requirements of the LIST command.
163.4880 -
163.4881 -   The LIST HEADERS command returns a list of fields that may be
163.4882 -   retrieved using the HDR command.
163.4883 -
163.4884 -   The information is returned as a multi-line data block following the
163.4885 -   215 response code and contains one line for each field name
163.4886 -   (excluding the trailing colon for headers and including the leading
163.4887 -   colon for metadata items).  If the implementation allows any header
163.4888 -   to be retrieved, it MUST NOT include any header names in the list but
163.4889 -   MUST include the special entry ":" (a single colon on its own).  It
163.4890 -   MUST still explicitly list any metadata items that are available.
163.4891 -   The order of items in the list is not significant; the server need
163.4892 -   not even consistently return the same order.  The list MAY be empty
163.4893 -   (though in this circumstance there is little point in providing the
163.4894 -   HDR command).
163.4895 -
163.4896 -   An implementation that also supports the OVER command SHOULD at least
163.4897 -   permit all the headers and metadata items listed in the output from
163.4898 -   the LIST OVERVIEW.FMT command.
163.4899 -
163.4900 -   If the server treats the first form of the HDR command (message-id
163.4901 -   specified) differently from the other two forms (range specified or
163.4902 -   current article number used) in respect of which headers or metadata
163.4903 -   items are available, then the following apply:
163.4904 -
163.4905 -   o  If the MSGID argument is specified, the results MUST be those
163.4906 -      available for the first form of the HDR command.
163.4907 -
163.4908 -   o  If the RANGE argument is specified, the results MUST be those
163.4909 -      available for the second and third forms of the HDR command.
163.4910 -
163.4911 -   o  If no argument is specified, the results MUST be those available
163.4912 -      in all forms of the HDR command (that is, it MUST only list those
163.4913 -      items listed in both the previous cases).
163.4914 -
163.4915 -   If the server does not treat the various forms differently, then it
163.4916 -   MUST ignore any argument and always produce the same results (though
163.4917 -   not necessarily always in the same order).
163.4918 -
163.4919 -   If the HDR command is not implemented, the meaning of the output from
163.4920 -   this command is not specified, but it must still meet the above
163.4921 -   syntactic requirements.
163.4922 -
163.4923 -
163.4924 -
163.4925 -
163.4926 -
163.4927 -
163.4928 -Feather                     Standards Track                    [Page 88]
163.4929 -
163.4930 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4931 -
163.4932 -
163.4933 -8.6.3.  Examples
163.4934 -
163.4935 -   Example of an implementation providing access to only a few headers:
163.4936 -
163.4937 -      [C] LIST HEADERS
163.4938 -      [S] 215 headers supported:
163.4939 -      [S] Subject
163.4940 -      [S] Message-ID
163.4941 -      [S] Xref
163.4942 -      [S] .
163.4943 -
163.4944 -   Example of an implementation providing access to the same fields as
163.4945 -   the first example in Section 8.4.3:
163.4946 -
163.4947 -      [C] CAPABILITIES
163.4948 -      [S] 101 Capability list:
163.4949 -      [S] VERSION 2
163.4950 -      [S] READER
163.4951 -      [S] OVER
163.4952 -      [S] HDR
163.4953 -      [S] LIST ACTIVE NEWSGROUPS HEADERS OVERVIEW.FMT
163.4954 -      [S] .
163.4955 -      [C] LIST HEADERS
163.4956 -      [S] 215 headers and metadata items supported:
163.4957 -      [S] Date
163.4958 -      [S] Distribution
163.4959 -      [S] From
163.4960 -      [S] Message-ID
163.4961 -      [S] References
163.4962 -      [S] Subject
163.4963 -      [S] Xref
163.4964 -      [S] :bytes
163.4965 -      [S] :lines
163.4966 -      [S] .
163.4967 -
163.4968 -   Example of an implementation providing access to all headers:
163.4969 -
163.4970 -      [C] LIST HEADERS
163.4971 -      [S] 215 metadata items supported:
163.4972 -      [S] :
163.4973 -      [S] :lines
163.4974 -      [S] :bytes
163.4975 -      [S] :x-article-number
163.4976 -      [S] .
163.4977 -
163.4978 -
163.4979 -
163.4980 -
163.4981 -
163.4982 -
163.4983 -
163.4984 -Feather                     Standards Track                    [Page 89]
163.4985 -
163.4986 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.4987 -
163.4988 -
163.4989 -   Example of an implementation distinguishing the first form of the HDR
163.4990 -   command from the other two forms:
163.4991 -
163.4992 -      [C] LIST HEADERS RANGE
163.4993 -      [S] 215 metadata items supported:
163.4994 -      [S] :
163.4995 -      [S] :lines
163.4996 -      [S] :bytes
163.4997 -      [S] .
163.4998 -      [C] LIST HEADERS MSGID
163.4999 -      [S] 215 headers and metadata items supported:
163.5000 -      [S] Date
163.5001 -      [S] Distribution
163.5002 -      [S] From
163.5003 -      [S] Message-ID
163.5004 -      [S] References
163.5005 -      [S] Subject
163.5006 -      [S] :lines
163.5007 -      [S] :bytes
163.5008 -      [S] :x-article-number
163.5009 -      [S] .
163.5010 -      [C] LIST HEADERS
163.5011 -      [S] 215 headers and metadata items supported:
163.5012 -      [S] Date
163.5013 -      [S] Distribution
163.5014 -      [S] From
163.5015 -      [S] Message-ID
163.5016 -      [S] References
163.5017 -      [S] Subject
163.5018 -      [S] :lines
163.5019 -      [S] :bytes
163.5020 -      [S] .
163.5021 -
163.5022 -   Note that :x-article-number does not appear in the last set of
163.5023 -   output.
163.5024 -
163.5025 -9.  Augmented BNF Syntax for NNTP
163.5026 -
163.5027 -9.1.  Introduction
163.5028 -
163.5029 -   Each of the following sections describes the syntax of a major
163.5030 -   element of NNTP.  This syntax extends and refines the descriptions
163.5031 -   elsewhere in this specification and should be given precedence when
163.5032 -   resolving apparent conflicts.  Note that ABNF [RFC4234] strings are
163.5033 -   case insensitive.  Non-terminals used in several places are defined
163.5034 -   in a separate section at the end.
163.5035 -
163.5036 -
163.5037 -
163.5038 -
163.5039 -
163.5040 -Feather                     Standards Track                    [Page 90]
163.5041 -
163.5042 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5043 -
163.5044 -
163.5045 -   Between them, the non-terminals <command-line>, <command-datastream>,
163.5046 -   <command-continuation>, and <response> specify the text that flows
163.5047 -   between client and server.  A consistent naming scheme is used in
163.5048 -   this document for the non-terminals relating to each command, and
163.5049 -   SHOULD be used by the specification of registered extensions.
163.5050 -
163.5051 -   For each command, the sequence is as follows:
163.5052 -
163.5053 -   o  The client sends an instance of <command-line>; the syntax for the
163.5054 -      EXAMPLE command is <example-command>.
163.5055 -
163.5056 -   o  If the client is one that immediately streams data, it sends an
163.5057 -      instance of <command-datastream>; the syntax for the EXAMPLE
163.5058 -      command is <example-datastream>.
163.5059 -
163.5060 -   o  The server sends an instance of <response>.
163.5061 -
163.5062 -      *  The initial response line is independent of the command that
163.5063 -         generated it; if the 000 response has arguments, the syntax of
163.5064 -         the initial line is <response-000-content>.
163.5065 -
163.5066 -      *  If the response is multi-line, the initial line is followed by
163.5067 -         a <multi-line-data-block>.  The syntax for the contents of this
163.5068 -         block after "dot-stuffing" has been removed is (for the 000
163.5069 -         response to the EXAMPLE command) <example-000-ml-content> and
163.5070 -         is an instance of <multi-line-response-content>.
163.5071 -
163.5072 -   o  While the latest response is one that indicates more data is
163.5073 -      required (in general, a 3xx response):
163.5074 -
163.5075 -      *  the client sends an instance of <command-continuation>; the
163.5076 -         syntax for the EXAMPLE continuation following a 333 response is
163.5077 -         <example-333-continuation>;
163.5078 -
163.5079 -      *  the server sends another instance of <response>, as above.
163.5080 -
163.5081 -   (There are no commands in this specification that immediately stream
163.5082 -   data, but this non-terminal is defined for the convenience of
163.5083 -   extensions.)
163.5084 -
163.5085 -
163.5086 -
163.5087 -
163.5088 -
163.5089 -
163.5090 -
163.5091 -
163.5092 -
163.5093 -
163.5094 -
163.5095 -
163.5096 -Feather                     Standards Track                    [Page 91]
163.5097 -
163.5098 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5099 -
163.5100 -
163.5101 -9.2.  Commands
163.5102 -
163.5103 -   This syntax defines the non-terminal <command-line>, which represents
163.5104 -   what is sent from the client to the server (see section 3.1 for
163.5105 -   limits on lengths).
163.5106 -
163.5107 -     command-line = command EOL
163.5108 -     command = X-command
163.5109 -     X-command = keyword *(WS token)
163.5110 -
163.5111 -     command =/ article-command /
163.5112 -           body-command /
163.5113 -           capabilities-command /
163.5114 -           date-command /
163.5115 -           group-command /
163.5116 -           hdr-command /
163.5117 -           head-command /
163.5118 -           help-command /
163.5119 -           ihave-command /
163.5120 -           last-command /
163.5121 -           list-command /
163.5122 -           listgroup-command /
163.5123 -           mode-reader-command /
163.5124 -           newgroups-command /
163.5125 -           newnews-command /
163.5126 -           next-command /
163.5127 -           over-command /
163.5128 -           post-command /
163.5129 -           quit-command /
163.5130 -           stat-command
163.5131 -
163.5132 -     article-command = "ARTICLE" [WS article-ref]
163.5133 -     body-command = "BODY" [WS article-ref]
163.5134 -     capabilities-command = "CAPABILITIES" [WS keyword]
163.5135 -     date-command = "DATE"
163.5136 -     group-command = "GROUP" [WS newsgroup-name]
163.5137 -     hdr-command = "HDR" WS header-meta-name [WS range-ref]
163.5138 -     head-command = "HEAD" [WS article-ref]
163.5139 -     help-command = "HELP"
163.5140 -     ihave-command = "IHAVE" WS message-id
163.5141 -     last-command = "LAST"
163.5142 -     list-command = "LIST" [WS list-arguments]
163.5143 -     listgroup-command = "LISTGROUP" [WS newsgroup-name [WS range]]
163.5144 -     mode-reader-command = "MODE" WS "READER"
163.5145 -     newgroups-command = "NEWGROUPS" WS date-time
163.5146 -     newnews-command = "NEWNEWS" WS wildmat WS date-time
163.5147 -     next-command = "NEXT"
163.5148 -     over-command = "OVER" [WS range-ref]
163.5149 -
163.5150 -
163.5151 -
163.5152 -Feather                     Standards Track                    [Page 92]
163.5153 -
163.5154 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5155 -
163.5156 -
163.5157 -     post-command = "POST"
163.5158 -     quit-command = "QUIT"
163.5159 -     stat-command = "STAT" [WS article-ref]
163.5160 -
163.5161 -     article-ref = article-number / message-id
163.5162 -     date = date2y / date4y
163.5163 -     date4y = 4DIGIT 2DIGIT 2DIGIT
163.5164 -     date2y = 2DIGIT 2DIGIT 2DIGIT
163.5165 -     date-time = date WS time [WS "GMT"]
163.5166 -     header-meta-name = header-name / metadata-name
163.5167 -     list-arguments = keyword [WS token]
163.5168 -     metadata-name = ":" 1*A-NOTCOLON
163.5169 -     range = article-number ["-" [article-number]]
163.5170 -     range-ref = range / message-id
163.5171 -     time = 2DIGIT 2DIGIT 2DIGIT
163.5172 -
163.5173 -9.3.  Command Continuation
163.5174 -
163.5175 -   This syntax defines the further material sent by the client in the
163.5176 -   case of multi-stage commands and those that stream data.
163.5177 -
163.5178 -     command-datastream = UNDEFINED
163.5179 -       ; not used, provided as a hook for extensions
163.5180 -     command-continuation = ihave-335-continuation /
163.5181 -           post-340-continuation
163.5182 -
163.5183 -     ihave-335-continuation = encoded-article
163.5184 -     post-340-continuation = encoded-article
163.5185 -
163.5186 -     encoded-article = multi-line-data-block
163.5187 -       ; after undoing the "dot-stuffing", this MUST match <article>
163.5188 -
163.5189 -9.4.  Responses
163.5190 -
163.5191 -9.4.1.  Generic Responses
163.5192 -
163.5193 -   This syntax defines the non-terminal <response>, which represents the
163.5194 -   generic form of responses; that is, what is sent from the server to
163.5195 -   the client in response to a <command> or a <command-continuation>.
163.5196 -
163.5197 -     response = simple-response / multi-line-response
163.5198 -     simple-response = initial-response-line
163.5199 -     multi-line-response = initial-response-line multi-line-data-block
163.5200 -
163.5201 -     initial-response-line =
163.5202 -           initial-response-content [SP trailing-comment] CRLF
163.5203 -     initial-response-content = X-initial-response-content
163.5204 -     X-initial-response-content = 3DIGIT *(SP response-argument)
163.5205 -
163.5206 -
163.5207 -
163.5208 -Feather                     Standards Track                    [Page 93]
163.5209 -
163.5210 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5211 -
163.5212 -
163.5213 -     response-argument = 1*A-CHAR
163.5214 -     trailing-comment = *U-CHAR
163.5215 -
163.5216 -9.4.2.  Initial Response Line Contents
163.5217 -
163.5218 -   This syntax defines the specific initial response lines for the
163.5219 -   various commands in this specification (see section 3.1 for limits on
163.5220 -   lengths).  Only those response codes with arguments are listed.
163.5221 -
163.5222 -     initial-response-content =/ response-111-content /
163.5223 -           response-211-content /
163.5224 -           response-220-content /
163.5225 -           response-221-content /
163.5226 -           response-222-content /
163.5227 -           response-223-content /
163.5228 -           response-401-content
163.5229 -
163.5230 -     response-111-content = "111" SP date4y time
163.5231 -     response-211-content = "211" 3(SP article-number) SP newsgroup-name
163.5232 -     response-220-content = "220" SP article-number SP message-id
163.5233 -     response-221-content = "221" SP article-number SP message-id
163.5234 -     response-222-content = "222" SP article-number SP message-id
163.5235 -     response-223-content = "223" SP article-number SP message-id
163.5236 -     response-401-content = "401" SP capability-label
163.5237 -
163.5238 -9.4.3.  Multi-line Response Contents
163.5239 -
163.5240 -   This syntax defines the content of the various multi-line responses;
163.5241 -   more precisely, it defines the part of the response in the multi-line
163.5242 -   data block after any "dot-stuffing" has been undone.  The numeric
163.5243 -   portion of each non-terminal name indicates the response code that is
163.5244 -   followed by this data.
163.5245 -
163.5246 -     multi-line-response-content = article-220-ml-content /
163.5247 -           body-222-ml-content /
163.5248 -           capabilities-101-ml-content /
163.5249 -           hdr-225-ml-content /
163.5250 -           head-221-ml-content /
163.5251 -           help-100-ml-content /
163.5252 -           list-215-ml-content /
163.5253 -           listgroup-211-ml-content /
163.5254 -           newgroups-231-ml-content /
163.5255 -           newnews-230-ml-content /
163.5256 -           over-224-ml-content
163.5257 -
163.5258 -     article-220-ml-content = article
163.5259 -     body-222-ml-content = body
163.5260 -     capabilities-101-ml-content = version-line CRLF
163.5261 -
163.5262 -
163.5263 -
163.5264 -Feather                     Standards Track                    [Page 94]
163.5265 -
163.5266 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5267 -
163.5268 -
163.5269 -           *(capability-line CRLF)
163.5270 -     hdr-225-ml-content = *(article-number SP hdr-content CRLF)
163.5271 -     head-221-ml-content = 1*header
163.5272 -     help-100-ml-content = *(*U-CHAR CRLF)
163.5273 -     list-215-ml-content = list-content
163.5274 -     listgroup-211-ml-content = *(article-number CRLF)
163.5275 -     newgroups-231-ml-content = active-groups-list
163.5276 -     newnews-230-ml-content = *(message-id CRLF)
163.5277 -     over-224-ml-content = *(article-number over-content CRLF)
163.5278 -
163.5279 -     active-groups-list = *(newsgroup-name SPA article-number
163.5280 -           SPA article-number SPA newsgroup-status CRLF)
163.5281 -     hdr-content = *S-NONTAB
163.5282 -     hdr-n-content = [(header-name ":" / metadata-name) SP hdr-content]
163.5283 -     list-content = body
163.5284 -     newsgroup-status = %x79 / %x6E / %x6D / private-status
163.5285 -     over-content = 1*6(TAB hdr-content) /
163.5286 -           7(TAB hdr-content) *(TAB hdr-n-content)
163.5287 -     private-status = token ; except the values in newsgroup-status
163.5288 -
163.5289 -9.5.  Capability Lines
163.5290 -
163.5291 -   This syntax defines the generic form of a capability line in the
163.5292 -   capabilities list (see Section 3.3.1).
163.5293 -
163.5294 -     capability-line = capability-entry
163.5295 -     capability-entry = X-capability-entry
163.5296 -     X-capability-entry = capability-label *(WS capability-argument)
163.5297 -     capability-label = keyword
163.5298 -     capability-argument = token
163.5299 -
163.5300 -   This syntax defines the specific capability entries for the
163.5301 -   capabilities in this specification.
163.5302 -
163.5303 -     capability-entry =/
163.5304 -           hdr-capability /
163.5305 -           ihave-capability /
163.5306 -           implementation-capability /
163.5307 -           list-capability /
163.5308 -           mode-reader-capability /
163.5309 -           newnews-capability /
163.5310 -           over-capability /
163.5311 -           post-capability /
163.5312 -           reader-capability
163.5313 -
163.5314 -     hdr-capability = "HDR"
163.5315 -     ihave-capability = "IHAVE"
163.5316 -     implementation-capability = "IMPLEMENTATION" *(WS token)
163.5317 -
163.5318 -
163.5319 -
163.5320 -Feather                     Standards Track                    [Page 95]
163.5321 -
163.5322 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5323 -
163.5324 -
163.5325 -     list-capability = "LIST" 1*(WS keyword)
163.5326 -     mode-reader-capability = "MODE-READER"
163.5327 -     newnews-capability = "NEWNEWS"
163.5328 -     over-capability = "OVER" [WS "MSGID"]
163.5329 -     post-capability = "POST"
163.5330 -     reader-capability = "READER"
163.5331 -
163.5332 -     version-line = "VERSION" 1*(WS version-number)
163.5333 -     version-number = nzDIGIT *5DIGIT
163.5334 -
163.5335 -9.6.  LIST Variants
163.5336 -
163.5337 -   This section defines more specifically the keywords for the LIST
163.5338 -   command and the syntax of the corresponding response contents.
163.5339 -
163.5340 -     ; active
163.5341 -     list-arguments =/ "ACTIVE" [WS wildmat]
163.5342 -     list-content =/ list-active-content
163.5343 -     list-active-content = active-groups-list
163.5344 -
163.5345 -
163.5346 -     ; active.times
163.5347 -     list-arguments =/ "ACTIVE.TIMES" [WS wildmat]
163.5348 -     list-content =/ list-active-times-content
163.5349 -     list-active-times-content =
163.5350 -           *(newsgroup-name SPA 1*DIGIT SPA newsgroup-creator CRLF)
163.5351 -     newsgroup-creator = U-TEXT
163.5352 -
163.5353 -
163.5354 -     ; distrib.pats
163.5355 -     list-arguments =/ "DISTRIB.PATS"
163.5356 -     list-content =/ list-distrib-pats-content
163.5357 -     list-distrib-pats-content =
163.5358 -           *(1*DIGIT ":" wildmat ":" distribution CRLF)
163.5359 -     distribution = token
163.5360 -
163.5361 -
163.5362 -     ; headers
163.5363 -     list-arguments =/ "HEADERS" [WS ("MSGID" / "RANGE")]
163.5364 -     list-content =/ list-headers-content
163.5365 -     list-headers-content = *(header-meta-name CRLF) /
163.5366 -           *((metadata-name / ":") CRLF)
163.5367 -
163.5368 -
163.5369 -     ; newsgroups
163.5370 -     list-arguments =/ "NEWSGROUPS" [WS wildmat]
163.5371 -     list-content =/ list-newsgroups-content
163.5372 -     list-newsgroups-content =
163.5373 -
163.5374 -
163.5375 -
163.5376 -Feather                     Standards Track                    [Page 96]
163.5377 -
163.5378 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5379 -
163.5380 -
163.5381 -           *(newsgroup-name WS newsgroup-description CRLF)
163.5382 -     newsgroup-description = S-TEXT
163.5383 -
163.5384 -
163.5385 -     ; overview.fmt
163.5386 -     list-arguments =/ "OVERVIEW.FMT"
163.5387 -     list-content =/ list-overview-fmt-content
163.5388 -     list-overview-fmt-content = "Subject:" CRLF
163.5389 -           "From:" CRLF
163.5390 -           "Date:" CRLF
163.5391 -           "Message-ID:" CRLF
163.5392 -           "References:" CRLF
163.5393 -           ( ":bytes" CRLF ":lines" / "Bytes:" CRLF "Lines:") CRLF
163.5394 -           *((header-name ":full" / metadata-name) CRLF)
163.5395 -
163.5396 -9.7.  Articles
163.5397 -
163.5398 -   This syntax defines the non-terminal <article>, which represents the
163.5399 -   format of an article as described in Section 3.6.
163.5400 -
163.5401 -     article = 1*header CRLF body
163.5402 -     header = header-name ":" [CRLF] SP header-content CRLF
163.5403 -     header-content = *(S-CHAR / [CRLF] WS)
163.5404 -     body = *(*B-CHAR CRLF)
163.5405 -
163.5406 -9.8.  General Non-terminals
163.5407 -
163.5408 -   These non-terminals are used at various places in the syntax and are
163.5409 -   collected here for convenience.  A few of these non-terminals are not
163.5410 -   used in this specification but are provided for the consistency and
163.5411 -   convenience of extension authors.
163.5412 -
163.5413 -     multi-line-data-block = content-lines termination
163.5414 -     content-lines = *([content-text] CRLF)
163.5415 -     content-text = (".." / B-NONDOT) *B-CHAR
163.5416 -     termination = "." CRLF
163.5417 -
163.5418 -     article-number = 1*16DIGIT
163.5419 -     header-name = 1*A-NOTCOLON
163.5420 -     keyword = ALPHA 2*(ALPHA / DIGIT / "." / "-")
163.5421 -     message-id = "<" 1*248A-NOTGT ">"
163.5422 -     newsgroup-name = 1*wildmat-exact
163.5423 -     token = 1*P-CHAR
163.5424 -
163.5425 -     wildmat = wildmat-pattern *("," ["!"] wildmat-pattern)
163.5426 -     wildmat-pattern = 1*wildmat-item
163.5427 -     wildmat-item = wildmat-exact / wildmat-wild
163.5428 -     wildmat-exact = %x22-29 / %x2B / %x2D-3E / %x40-5A / %x5E-7E /
163.5429 -
163.5430 -
163.5431 -
163.5432 -Feather                     Standards Track                    [Page 97]
163.5433 -
163.5434 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5435 -
163.5436 -
163.5437 -          UTF8-non-ascii  ; exclude ! * , ? [ \ ]
163.5438 -     wildmat-wild = "*" / "?"
163.5439 -
163.5440 -     base64 = *(4base64-char) [base64-terminal]
163.5441 -     base64-char = UPPER / LOWER / DIGIT / "+" / "/"
163.5442 -     base64-terminal = 2base64-char "==" / 3base64-char "="
163.5443 -
163.5444 -     ; Assorted special character sets
163.5445 -     ;   A- means based on US-ASCII, excluding controls and SP
163.5446 -     ;   P- means based on UTF-8, excluding controls and SP
163.5447 -     ;   U- means based on UTF-8, excluding NUL CR and LF
163.5448 -     ;   B- means based on bytes, excluding NUL CR and LF
163.5449 -     A-CHAR     = %x21-7E
163.5450 -     A-NOTCOLON = %x21-39 / %x3B-7E  ; exclude ":"
163.5451 -     A-NOTGT    = %x21-3D / %x3F-7E  ; exclude ">"
163.5452 -     P-CHAR     = A-CHAR / UTF8-non-ascii
163.5453 -     U-CHAR     = CTRL / TAB / SP / A-CHAR / UTF8-non-ascii
163.5454 -     U-NONTAB   = CTRL /       SP / A-CHAR / UTF8-non-ascii
163.5455 -     U-TEXT     = P-CHAR *U-CHAR
163.5456 -     B-CHAR     = CTRL / TAB / SP / %x21-FF
163.5457 -     B-NONDOT   = CTRL / TAB / SP / %x21-2D / %x2F-FF  ; exclude "."
163.5458 -
163.5459 -     ALPHA = UPPER / LOWER   ; use only when case-insensitive
163.5460 -     CR = %x0D
163.5461 -     CRLF = CR LF
163.5462 -     CTRL = %x01-08 / %x0B-0C / %x0E-1F
163.5463 -     DIGIT = %x30-39
163.5464 -     nzDIGIT = %x31-39
163.5465 -     EOL = *(SP / TAB) CRLF
163.5466 -     LF = %x0A
163.5467 -     LOWER = %x61-7A
163.5468 -     SP = %x20
163.5469 -     SPA = 1*SP
163.5470 -     TAB = %x09
163.5471 -     UPPER = %x41-5A
163.5472 -     UTF8-non-ascii = UTF8-2 / UTF8-3 / UTF8-4
163.5473 -     UTF8-2    = %xC2-DF UTF8-tail
163.5474 -     UTF8-3    = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2UTF8-tail /
163.5475 -                 %xED %x80-9F UTF8-tail / %xEE-EF 2UTF8-tail
163.5476 -     UTF8-4    = %xF0 %x90-BF 2UTF8-tail / %xF1-F3 3UTF8-tail /
163.5477 -                 %xF4 %x80-8F 2UTF8-tail
163.5478 -     UTF8-tail = %x80-BF
163.5479 -     WS = 1*(SP / TAB)
163.5480 -
163.5481 -   The following non-terminals require special consideration.  They
163.5482 -   represent situations where material SHOULD be restricted to UTF-8,
163.5483 -   but implementations MUST be able to cope with other character
163.5484 -   encodings.  Therefore, there are two sets of definitions for them.
163.5485 -
163.5486 -
163.5487 -
163.5488 -Feather                     Standards Track                    [Page 98]
163.5489 -
163.5490 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5491 -
163.5492 -
163.5493 -   Implementations MUST accept any content that meets this syntax:
163.5494 -
163.5495 -     S-CHAR   = %x21-FF
163.5496 -     S-NONTAB = CTRL / SP / S-CHAR
163.5497 -     S-TEXT   = (CTRL / S-CHAR) *B-CHAR
163.5498 -
163.5499 -   and MAY pass such content on unaltered.
163.5500 -
163.5501 -   When generating new content or re-encoding existing content,
163.5502 -   implementations SHOULD conform to this syntax:
163.5503 -
163.5504 -     S-CHAR   = P-CHAR
163.5505 -     S-NONTAB = U-NONTAB
163.5506 -     S-TEXT   = U-TEXT
163.5507 -
163.5508 -9.9.  Extensions and Validation
163.5509 -
163.5510 -   The specification of a registered extension MUST include formal
163.5511 -   syntax that defines additional forms for the following non-terminals:
163.5512 -
163.5513 -   command
163.5514 -      for each new command other than a variant of the LIST command -
163.5515 -      the syntax of each command MUST be compatible with the definition
163.5516 -      of <X-command>;
163.5517 -
163.5518 -   command-datastream
163.5519 -      for each new command that immediately streams data;
163.5520 -
163.5521 -   command-continuation
163.5522 -      for each new command that sends further material after the initial
163.5523 -      command line - the syntax of each continuation MUST be exactly
163.5524 -      what is sent to the server, including any escape mechanisms such
163.5525 -      as "dot-stuffing";
163.5526 -
163.5527 -   initial-response-content
163.5528 -      for each new response code that has arguments - the syntax of each
163.5529 -      response MUST be compatible with the definition of <X-initial-
163.5530 -      response-content>;
163.5531 -
163.5532 -   multi-line-response-content
163.5533 -      for each new response code that has a multi-line response - the
163.5534 -      syntax MUST show the response after the lines containing the
163.5535 -      response code and the terminating octet have been removed and any
163.5536 -      "dot-stuffing" undone;
163.5537 -
163.5538 -   capability-entry
163.5539 -      for each new capability label - the syntax of each entry MUST be
163.5540 -      compatible with the definition of <X-capability-entry>;
163.5541 -
163.5542 -
163.5543 -
163.5544 -Feather                     Standards Track                    [Page 99]
163.5545 -
163.5546 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5547 -
163.5548 -
163.5549 -   list-arguments
163.5550 -      for each new variant of the LIST command - the syntax of each
163.5551 -      entry MUST be compatible with the definition of <X-command>;
163.5552 -
163.5553 -   list-content
163.5554 -      for each new variant of the LIST command - the syntax MUST show
163.5555 -      the response after the lines containing the 215 response code and
163.5556 -      the terminating octet have been removed and any "dot-stuffing"
163.5557 -      undone.
163.5558 -
163.5559 -   The =/ notation of ABNF [RFC4234] and the naming conventions
163.5560 -   described in Section 9.1 SHOULD be used for this.
163.5561 -
163.5562 -   When the syntax in this specification, or syntax based on it, is
163.5563 -   validated, it should be noted that:
163.5564 -
163.5565 -   o  the non-terminals <command-line>, <command-datastream>,
163.5566 -      <command-continuation>, <response>, and
163.5567 -      <multi-line-response-content> describe basic concepts of the
163.5568 -      protocol and are not referred to by any other rule;
163.5569 -
163.5570 -   o  the non-terminal <base64> is provided for the convenience of
163.5571 -      extension authors and is not referred to by any rule in this
163.5572 -      specification;
163.5573 -
163.5574 -   o  for the reasons given above, the non-terminals <S-CHAR>,
163.5575 -      <S-NONTAB>, and <S-TEXT> each have two definitions; and
163.5576 -
163.5577 -   o  the non-terminal <UNDEFINED> is deliberately not defined.
163.5578 -
163.5579 -10.  Internationalisation Considerations
163.5580 -
163.5581 -10.1.  Introduction and Historical Situation
163.5582 -
163.5583 -   RFC 977 [RFC977] was written at a time when internationalisation was
163.5584 -   not seen as a significant issue.  As such, it was written on the
163.5585 -   assumption that all communication would be in ASCII and use only a
163.5586 -   7-bit transport layer, although in practice just about all known
163.5587 -   implementations are 8-bit clean.
163.5588 -
163.5589 -   Since then, Usenet and NNTP have spread throughout the world.  In the
163.5590 -   absence of standards for handling the issues of language and
163.5591 -   character sets, countries, newsgroup hierarchies, and individuals
163.5592 -   have found a variety of solutions that work for them but that are not
163.5593 -   necessarily appropriate elsewhere.  For example, some have adopted a
163.5594 -   default 8-bit character set appropriate to their needs (such as
163.5595 -   ISO/IEC 8859-1 in Western Europe or KOI-8 in Russia), others have
163.5596 -   used ASCII (either US-ASCII or national variants) in headers but
163.5597 -
163.5598 -
163.5599 -
163.5600 -Feather                     Standards Track                   [Page 100]
163.5601 -
163.5602 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5603 -
163.5604 -
163.5605 -   local 16-bit character sets in article bodies, and still others have
163.5606 -   gone for a combination of MIME [RFC2045] and UTF-8.  With the
163.5607 -   increased use of MIME in email, it is becoming more common to find
163.5608 -   NNTP articles containing MIME headers that identify the character set
163.5609 -   of the body, but this is far from universal.
163.5610 -
163.5611 -   The resulting confusion does not help interoperability.
163.5612 -
163.5613 -   One point that has been generally accepted is that articles can
163.5614 -   contain octets with the top bit set, and NNTP is only expected to
163.5615 -   operate on 8-bit clean transport paths.
163.5616 -
163.5617 -10.2.  This Specification
163.5618 -
163.5619 -   Part of the role of this present specification is to eliminate this
163.5620 -   confusion and promote interoperability as far as possible.  At the
163.5621 -   same time, it is necessary to accept the existence of the present
163.5622 -   situation and not break existing implementations and arrangements
163.5623 -   gratuitously, even if they are less than optimal.  Therefore, the
163.5624 -   current practice described above has been taken into consideration in
163.5625 -   producing this specification.
163.5626 -
163.5627 -   This specification extends NNTP from US-ASCII [ANSI1986] to UTF-8
163.5628 -   [RFC3629].  Except in the two areas discussed below, UTF-8 (which is
163.5629 -   a superset of US-ASCII) is mandatory, and implementations MUST NOT
163.5630 -   use any other encoding.
163.5631 -
163.5632 -   Firstly, the use of MIME for article headers and bodies is strongly
163.5633 -   recommended.  However, given widely divergent existing practices, an
163.5634 -   attempt to require a particular encoding and tagging standard would
163.5635 -   be premature at this time.  Accordingly, this specification allows
163.5636 -   the use of arbitrary 8-bit data in articles subject to the following
163.5637 -   requirements and recommendations.
163.5638 -
163.5639 -   o  The names of headers (e.g., "From" or "Subject") MUST be in
163.5640 -      US-ASCII.
163.5641 -
163.5642 -   o  Header values SHOULD use US-ASCII or an encoding based on it, such
163.5643 -      as RFC 2047 [RFC2047], until such time as another approach has
163.5644 -      been standardised.  At present, 8-bit encodings (including UTF-8)
163.5645 -      SHOULD NOT be used because they are likely to cause
163.5646 -      interoperability problems.
163.5647 -
163.5648 -   o  The character set of article bodies SHOULD be indicated in the
163.5649 -      article headers, and this SHOULD be done in accordance with MIME.
163.5650 -
163.5651 -   o  Where an article is obtained from an external source, an
163.5652 -      implementation MAY pass it on and derive data from it (such as the
163.5653 -
163.5654 -
163.5655 -
163.5656 -Feather                     Standards Track                   [Page 101]
163.5657 -
163.5658 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5659 -
163.5660 -
163.5661 -      response to the HDR command), even though the article or the data
163.5662 -      does not meet the above requirements.  Implementations MUST
163.5663 -      transfer such articles and data correctly and unchanged; they MUST
163.5664 -      NOT attempt to convert or re-encode the article or derived data.
163.5665 -      (Nevertheless, a client or server MAY elect not to post or forward
163.5666 -      the article if, after further examination of the article, it deems
163.5667 -      it inappropriate to do so.)
163.5668 -
163.5669 -   This requirement affects the ARTICLE (Section 6.2.1), BODY
163.5670 -   (Section 6.2.3), HDR (Section 8.5), HEAD (Section 6.2.2), IHAVE
163.5671 -   (Section 6.3.2), OVER (Section 8.3), and POST (Section 6.3.1)
163.5672 -   commands.
163.5673 -
163.5674 -   Secondly, the following requirements are placed on the newsgroups
163.5675 -   list returned by the LIST NEWSGROUPS command (Section 7.6.6):
163.5676 -
163.5677 -   o  Although this specification allows UTF-8 for newsgroup names, they
163.5678 -      SHOULD be restricted to US-ASCII until a successor to RFC 1036
163.5679 -      [RFC1036] standardises another approach. 8-bit encodings SHOULD
163.5680 -      NOT be used because they are likely to cause interoperability
163.5681 -      problems.
163.5682 -
163.5683 -   o  The newsgroup description SHOULD be in US-ASCII or UTF-8 unless
163.5684 -      and until a successor to RFC 1036 standardises other encoding
163.5685 -      arrangements.  8-bit encodings other than UTF-8 SHOULD NOT be used
163.5686 -      because they are likely to cause interoperability problems.
163.5687 -
163.5688 -   o  Implementations that obtain this data from an external source MUST
163.5689 -      handle it correctly even if it does not meet the above
163.5690 -      requirements.  Implementations (in particular, clients) MUST
163.5691 -      handle such data correctly.
163.5692 -
163.5693 -10.3.  Outstanding Issues
163.5694 -
163.5695 -   While the primary use of NNTP is for transmitting articles that
163.5696 -   conform to RFC 1036 (Netnews articles), it is also used for other
163.5697 -   formats (see Appendix A).  It is therefore most appropriate that
163.5698 -   internationalisation issues related to article formats be addressed
163.5699 -   in the relevant specifications.  For Netnews articles, this is any
163.5700 -   successor to RFC 1036.  For email messages, it is RFC 2822 [RFC2822].
163.5701 -
163.5702 -   Of course, any article transmitted via NNTP needs to conform to this
163.5703 -   specification as well.
163.5704 -
163.5705 -   Restricting newsgroup names to UTF-8 is not a complete solution.  In
163.5706 -   particular, when new newsgroup names are created or a user is asked
163.5707 -   to enter a newsgroup name, some scheme of canonicalisation will need
163.5708 -   to take place.  This specification does not attempt to define that
163.5709 -
163.5710 -
163.5711 -
163.5712 -Feather                     Standards Track                   [Page 102]
163.5713 -
163.5714 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5715 -
163.5716 -
163.5717 -   canonicalization; further work is needed in this area, in conjunction
163.5718 -   with the article format specifications.  Until such specifications
163.5719 -   are published, implementations SHOULD match newsgroup names octet by
163.5720 -   octet.  It is anticipated that any approved scheme will be applied
163.5721 -   "at the edges", and therefore octet-by-octet comparison will continue
163.5722 -   to apply to most, if not all, uses of newsgroup names in NNTP.
163.5723 -
163.5724 -   In the meantime, any implementation experimenting with UTF-8
163.5725 -   newsgroup names is strongly cautioned that a future specification may
163.5726 -   require that those names be canonicalized when used with NNTP in a
163.5727 -   way that is not compatible with their experiments.
163.5728 -
163.5729 -   Since the primary use of NNTP is with Netnews, and since newsgroup
163.5730 -   descriptions are normally distributed through specially formatted
163.5731 -   articles, it is recommended that the internationalisation issues
163.5732 -   related to them be addressed in any successor to RFC 1036.
163.5733 -
163.5734 -11.  IANA Considerations
163.5735 -
163.5736 -   This specification requires IANA to keep a registry of capability
163.5737 -   labels.  The initial contents of this registry are specified in
163.5738 -   Section 3.3.4.  As described in Section 3.3.3, labels beginning with
163.5739 -   X are reserved for private use, while all other names are expected to
163.5740 -   be associated with a specification in an RFC on the standards track
163.5741 -   or defining an IESG-approved experimental protocol.
163.5742 -
163.5743 -   Different entries in the registry MUST use different capability
163.5744 -   labels.
163.5745 -
163.5746 -   Different entries in the registry MUST NOT use the same command name.
163.5747 -   For this purpose, variants distinguished by a second or subsequent
163.5748 -   keyword (e.g., "LIST HEADERS" and "LIST OVERVIEW.FMT") count as
163.5749 -   different commands.  If there is a need for two extensions to use the
163.5750 -   same command, a single harmonised specification MUST be registered.
163.5751 -
163.5752 -12.  Security Considerations
163.5753 -
163.5754 -   This section is meant to inform application developers, information
163.5755 -   providers, and users of the security limitations in NNTP as described
163.5756 -   by this document.  The discussion does not include definitive
163.5757 -   solutions to the problems revealed, though it does make some
163.5758 -   suggestions for reducing security risks.
163.5759 -
163.5760 -
163.5761 -
163.5762 -
163.5763 -
163.5764 -
163.5765 -
163.5766 -
163.5767 -
163.5768 -Feather                     Standards Track                   [Page 103]
163.5769 -
163.5770 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5771 -
163.5772 -
163.5773 -12.1.  Personal and Proprietary Information
163.5774 -
163.5775 -   NNTP, because it was created to distribute network news articles,
163.5776 -   will forward whatever information is stored in those articles.
163.5777 -   Specification of that information is outside this scope of this
163.5778 -   document, but it is likely that some personal and/or proprietary
163.5779 -   information is available in some of those articles.  It is very
163.5780 -   important that designers and implementers provide informative
163.5781 -   warnings to users so that personal and/or proprietary information in
163.5782 -   material that is added automatically to articles (e.g., in headers)
163.5783 -   is not disclosed inadvertently.  Additionally, effective and easily
163.5784 -   understood mechanisms to manage the distribution of news articles
163.5785 -   SHOULD be provided to NNTP Server administrators, so that they are
163.5786 -   able to report with confidence the likely spread of any particular
163.5787 -   set of news articles.
163.5788 -
163.5789 -12.2.  Abuse of Server Log Information
163.5790 -
163.5791 -   A server is in the position to save session data about a user's
163.5792 -   requests that might identify their reading patterns or subjects of
163.5793 -   interest.  This information is clearly confidential in nature, and
163.5794 -   its handling can be constrained by law in certain countries.  People
163.5795 -   using this protocol to provide data are responsible for ensuring that
163.5796 -   such material is not distributed without the permission of any
163.5797 -   individuals that are identifiable by the published results.
163.5798 -
163.5799 -12.3.  Weak Authentication and Access Control
163.5800 -
163.5801 -   There is no user-based or token-based authentication in the basic
163.5802 -   NNTP specification.  Access is normally controlled by server
163.5803 -   configuration files.  Those files specify access by using domain
163.5804 -   names or IP addresses.  However, this specification does permit the
163.5805 -   creation of extensions to NNTP for such purposes; one such extension
163.5806 -   is [NNTP-AUTH].  While including such mechanisms is optional, doing
163.5807 -   so is strongly encouraged.
163.5808 -
163.5809 -   Other mechanisms are also available.  For example, a proxy server
163.5810 -   could be put in place that requires authentication before connecting
163.5811 -   via the proxy to the NNTP server.
163.5812 -
163.5813 -12.4.  DNS Spoofing
163.5814 -
163.5815 -   Many existing NNTP implementations authorize incoming connections by
163.5816 -   checking the IP address of that connection against the IP addresses
163.5817 -   obtained via DNS lookups of lists of domain names given in local
163.5818 -   configuration files.  Servers that use this type of authentication
163.5819 -   and clients that find a server by doing a DNS lookup of the server
163.5820 -   name rely very heavily on the Domain Name Service, and are thus
163.5821 -
163.5822 -
163.5823 -
163.5824 -Feather                     Standards Track                   [Page 104]
163.5825 -
163.5826 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5827 -
163.5828 -
163.5829 -   generally prone to security attacks based on the deliberate
163.5830 -   misassociation of IP addresses and DNS names.  Clients and servers
163.5831 -   need to be cautious in assuming the continuing validity of an IP
163.5832 -   number/DNS name association.
163.5833 -
163.5834 -   In particular, NNTP clients and servers SHOULD rely on their name
163.5835 -   resolver for confirmation of an IP number/DNS name association,
163.5836 -   rather than cache the result of previous host name lookups.  Many
163.5837 -   platforms already can cache host name lookups locally when
163.5838 -   appropriate, and they SHOULD be configured to do so.  It is proper
163.5839 -   for these lookups to be cached, however, only when the TTL (Time To
163.5840 -   Live) information reported by the name server makes it likely that
163.5841 -   the cached information will remain useful.
163.5842 -
163.5843 -   If NNTP clients or servers cache the results of host name lookups in
163.5844 -   order to achieve a performance improvement, they MUST observe the TTL
163.5845 -   information reported by DNS.  If NNTP clients or servers do not
163.5846 -   observe this rule, they could be spoofed when a previously accessed
163.5847 -   server's IP address changes.  As network renumbering is expected to
163.5848 -   become increasingly common, the possibility of this form of attack
163.5849 -   will increase.  Observing this requirement thus reduces this
163.5850 -   potential security vulnerability.
163.5851 -
163.5852 -   This requirement also improves the load-balancing behaviour of
163.5853 -   clients for replicated servers using the same DNS name and reduces
163.5854 -   the likelihood of a user's experiencing failure in accessing sites
163.5855 -   that use that strategy.
163.5856 -
163.5857 -12.5.  UTF-8 Issues
163.5858 -
163.5859 -   UTF-8 [RFC3629] permits only certain sequences of octets and
163.5860 -   designates others as either malformed or "illegal".  The Unicode
163.5861 -   standard identifies a number of security issues related to illegal
163.5862 -   sequences and forbids their generation by conforming implementations.
163.5863 -
163.5864 -   Implementations of this specification MUST NOT generate malformed or
163.5865 -   illegal sequences and SHOULD detect them and take some appropriate
163.5866 -   action.  This could include the following:
163.5867 -
163.5868 -   o  Generating a 501 response code.
163.5869 -
163.5870 -   o  Replacing such sequences by the sequence %xEF.BF.BD, which encodes
163.5871 -      the "replacement character" U+FFFD.
163.5872 -
163.5873 -   o  Closing the connection.
163.5874 -
163.5875 -   o  Replacing such sequences by a "guessed" valid sequence (based on
163.5876 -      properties of the UTF-8 encoding).
163.5877 -
163.5878 -
163.5879 -
163.5880 -Feather                     Standards Track                   [Page 105]
163.5881 -
163.5882 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5883 -
163.5884 -
163.5885 -   In the last case, the implementation MUST ensure that any replacement
163.5886 -   cannot be used to bypass validity or security checks.  For example,
163.5887 -   the illegal sequence %xC0.A0 is an over-long encoding for space
163.5888 -   (%x20).  If it is replaced by the correct encoding in a command line,
163.5889 -   this needs to happen before the command line is parsed into
163.5890 -   individual arguments.  If the replacement came after parsing, it
163.5891 -   would be possible to generate an argument with an embedded space,
163.5892 -   which is forbidden.  Use of the "replacement character" does not have
163.5893 -   this problem, since it is permitted wherever non-US-ASCII characters
163.5894 -   are.  Implementations SHOULD use one of the first two solutions where
163.5895 -   the general structure of the NNTP stream remains intact and SHOULD
163.5896 -   close the connection if it is no longer possible to parse it
163.5897 -   sensibly.
163.5898 -
163.5899 -12.6.  Caching of Capability Lists
163.5900 -
163.5901 -   The CAPABILITIES command provides a capability list, which is
163.5902 -   information about the current capabilities of the server.  Whenever
163.5903 -   there is a relevant change to the server state, the results of this
163.5904 -   command are required to change accordingly.
163.5905 -
163.5906 -   In most situations, the capabilities list in a given server state
163.5907 -   will not change from session to session; for example, a given
163.5908 -   extension will be installed permanently on a server.  Some clients
163.5909 -   may therefore wish to remember which extensions a server supports to
163.5910 -   avoid the delay of an additional command and response, particularly
163.5911 -   if they open multiple connections in the same session.
163.5912 -
163.5913 -   However, information about extensions related to security and privacy
163.5914 -   MUST NOT be cached, since this could allow a variety of attacks.
163.5915 -
163.5916 -   For example, consider a server that permits the use of cleartext
163.5917 -   passwords on links that are encrypted but not otherwise:
163.5918 -
163.5919 -      [Initial connection set-up completed.]
163.5920 -      [S] 200 NNTP Service Ready, posting permitted
163.5921 -      [C] CAPABILITIES
163.5922 -      [S] 101 Capability list:
163.5923 -      [S] VERSION 2
163.5924 -      [S] READER
163.5925 -      [S] NEWNEWS
163.5926 -      [S] POST
163.5927 -      [S] XENCRYPT
163.5928 -      [S] LIST ACTIVE NEWSGROUPS
163.5929 -      [S] .
163.5930 -      [C] XENCRYPT
163.5931 -      [Client and server negotiate encryption on the link]
163.5932 -      [S] 283 Encrypted link established
163.5933 -
163.5934 -
163.5935 -
163.5936 -Feather                     Standards Track                   [Page 106]
163.5937 -
163.5938 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5939 -
163.5940 -
163.5941 -      [C] CAPABILITIES
163.5942 -      [S] 101 Capability list:
163.5943 -      [S] VERSION 2
163.5944 -      [S] READER
163.5945 -      [S] NEWNEWS
163.5946 -      [S] POST
163.5947 -      [S] XSECRET
163.5948 -      [S] LIST ACTIVE NEWSGROUPS
163.5949 -      [S] .
163.5950 -      [C] XSECRET fred flintstone
163.5951 -      [S] 290 Password for fred accepted
163.5952 -
163.5953 -   If the client caches the last capabilities list, then on the next
163.5954 -   session it will attempt to use XSECRET on an unencrypted link:
163.5955 -
163.5956 -      [Initial connection set-up completed.]
163.5957 -      [S] 200 NNTP Service Ready, posting permitted
163.5958 -      [C] XSECRET fred flintstone
163.5959 -      [S] 483 Only permitted on secure links
163.5960 -
163.5961 -   This exposes the password to any eavesdropper.  While the primary
163.5962 -   cause of this is passing a secret without first checking the security
163.5963 -   of the link, caching of capability lists can increase the risk.
163.5964 -
163.5965 -   Any security extension should include requirements to check the
163.5966 -   security state of the link in a manner appropriate to that extension.
163.5967 -
163.5968 -   Caching should normally only be considered for anonymous clients that
163.5969 -   do not use any security or privacy extensions and for which the time
163.5970 -   required for an additional command and response is a noticeable
163.5971 -   issue.
163.5972 -
163.5973 -13.  Acknowledgements
163.5974 -
163.5975 -   This document is the result of much effort by the present and past
163.5976 -   members of the NNTP Working Group, chaired by Russ Allbery and Ned
163.5977 -   Freed.  It could not have been produced without them.
163.5978 -
163.5979 -   The author acknowledges the original authors of NNTP as documented in
163.5980 -   RFC 977 [RFC977]: Brian Kantor and Phil Lapsey.
163.5981 -
163.5982 -   The author gratefully acknowledges the following:
163.5983 -
163.5984 -   o  The work of the NNTP committee chaired by Eliot Lear.  The
163.5985 -      organization of this document was influenced by the last available
163.5986 -      version from this working group.  A special thanks to Eliot for
163.5987 -      generously providing the original machine-readable sources for
163.5988 -      that document.
163.5989 -
163.5990 -
163.5991 -
163.5992 -Feather                     Standards Track                   [Page 107]
163.5993 -
163.5994 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.5995 -
163.5996 -
163.5997 -   o  The work of the DRUMS working group, specifically RFC 1869
163.5998 -      [RFC1869], that drove the original thinking that led to the
163.5999 -      CAPABILITIES command and the extensions mechanism detailed in this
163.6000 -      document.
163.6001 -
163.6002 -   o  The authors of RFC 2616 [RFC2616] for providing specific and
163.6003 -      relevant examples of security issues that should be considered for
163.6004 -      HTTP.  Since many of the same considerations exist for NNTP, those
163.6005 -      examples that are relevant have been included here with some minor
163.6006 -      rewrites.
163.6007 -
163.6008 -   o  The comments and additional information provided by the following
163.6009 -      individuals in preparing one or more of the progenitors of this
163.6010 -      document:
163.6011 -
163.6012 -         Russ Allbery <rra@stanford.edu>
163.6013 -         Wayne Davison <davison@armory.com>
163.6014 -         Chris Lewis <clewis@bnr.ca>
163.6015 -         Tom Limoncelli <tal@mars.superlink.net>
163.6016 -         Eric Schnoebelen <eric@egsner.cirr.com>
163.6017 -         Rich Salz <rsalz@osf.org>
163.6018 -
163.6019 -   This work was motivated by the work of various news reader authors
163.6020 -   and news server authors, including those listed below:
163.6021 -
163.6022 -   Rick Adams
163.6023 -      Original author of the NNTP extensions to the RN news reader and
163.6024 -      last maintainer of Bnews.
163.6025 -
163.6026 -   Stan Barber
163.6027 -      Original author of the NNTP extensions to the news readers that
163.6028 -      are part of Bnews.
163.6029 -
163.6030 -   Geoff Collyer
163.6031 -      Original author of the OVERVIEW database proposal and one of the
163.6032 -      original authors of CNEWS.
163.6033 -
163.6034 -   Dan Curry
163.6035 -      Original author of the xvnews news reader.
163.6036 -
163.6037 -   Wayne Davison
163.6038 -      Author of the first threading extensions to the RN news reader
163.6039 -      (commonly called TRN).
163.6040 -
163.6041 -   Geoff Huston
163.6042 -      Original author of ANU NEWS.
163.6043 -
163.6044 -
163.6045 -
163.6046 -
163.6047 -
163.6048 -Feather                     Standards Track                   [Page 108]
163.6049 -
163.6050 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6051 -
163.6052 -
163.6053 -   Phil Lapsey
163.6054 -      Original author of the UNIX reference implementation for NNTP.
163.6055 -
163.6056 -   Iain Lea
163.6057 -      Original maintainer of the TIN news reader.
163.6058 -
163.6059 -   Chris Lewis
163.6060 -      First known implementer of the AUTHINFO GENERIC extension.
163.6061 -
163.6062 -   Rich Salz
163.6063 -      Original author of INN.
163.6064 -
163.6065 -   Henry Spencer
163.6066 -      One of the original authors of CNEWS.
163.6067 -
163.6068 -   Kim Storm
163.6069 -      Original author of the NN news reader.
163.6070 -
163.6071 -   Other people who contributed to this document include:
163.6072 -
163.6073 -      Matthias Andree
163.6074 -      Greg Andruk
163.6075 -      Daniel Barclay
163.6076 -      Maurizio Codogno
163.6077 -      Mark Crispin
163.6078 -      Andrew Gierth
163.6079 -      Juergen Helbing
163.6080 -      Scott Hollenbeck
163.6081 -      Urs Janssen
163.6082 -      Charles Lindsey
163.6083 -      Ade Lovett
163.6084 -      David Magda
163.6085 -      Ken Murchison
163.6086 -      Francois Petillon
163.6087 -      Peter Robinson
163.6088 -      Rob Siemborski
163.6089 -      Howard Swinehart
163.6090 -      Ruud van Tol
163.6091 -      Jeffrey Vinocur
163.6092 -      Erik Warmelink
163.6093 -
163.6094 -   The author thanks them all and apologises to anyone omitted.
163.6095 -
163.6096 -   Finally, the present author gratefully acknowledges the vast amount
163.6097 -   of work put into previous versions by the previous author:
163.6098 -
163.6099 -      Stan Barber <sob@academ.com>
163.6100 -
163.6101 -
163.6102 -
163.6103 -
163.6104 -Feather                     Standards Track                   [Page 109]
163.6105 -
163.6106 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6107 -
163.6108 -
163.6109 -14.  References
163.6110 -
163.6111 -14.1.  Normative References
163.6112 -
163.6113 -   [ANSI1986]    American National Standards Institute, "Coded Character
163.6114 -                 Set - 7-bit American Standard Code for Information
163.6115 -                 Interchange", ANSI X3.4, 1986.
163.6116 -
163.6117 -   [RFC977]      Kantor, B. and P. Lapsley, "Network News Transfer
163.6118 -                 Protocol", RFC 977, February 1986.
163.6119 -
163.6120 -   [RFC2045]     Freed, N. and N. Borenstein, "Multipurpose Internet
163.6121 -                 Mail Extensions (MIME) Part One: Format of Internet
163.6122 -                 Message Bodies", RFC 2045, November 1996.
163.6123 -
163.6124 -   [RFC2047]     Moore, K., "MIME (Multipurpose Internet Mail
163.6125 -                 Extensions) Part Three: Message Header Extensions for
163.6126 -                 Non-ASCII Text", RFC 2047, November 1996.
163.6127 -
163.6128 -   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
163.6129 -                 Requirement Levels", BCP 14, RFC 2119, March 1997.
163.6130 -
163.6131 -   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
163.6132 -                 10646", STD 63, RFC 3629, November 2003.
163.6133 -
163.6134 -   [RFC4234]     Crocker, D., Ed. and P. Overell, "Augmented BNF for
163.6135 -                 Syntax Specifications: ABNF", RFC 4234, October 2005.
163.6136 -
163.6137 -   [RFC4648]     Josefsson, S., "The Base16, Base32, and Base64 Data
163.6138 -                 Encodings", RFC 4648, October 2006.
163.6139 -
163.6140 -   [TF.686-1]    International Telecommunications Union - Radio,
163.6141 -                 "Glossary, ITU-R Recommendation TF.686-1",
163.6142 -                 ITU-R Recommendation TF.686-1, October 1997.
163.6143 -
163.6144 -14.2.  Informative References
163.6145 -
163.6146 -   [NNTP-AUTH]   Vinocur, J., Murchison, K., and C. Newman, "Network
163.6147 -                 News Transfer Protocol (NNTP) Extension for
163.6148 -                 Authentication",
163.6149 -                 RFC 4643, October 2006.
163.6150 -
163.6151 -   [NNTP-STREAM] Vinocur, J. and K. Murchison, "Network News Transfer
163.6152 -                 Protocol (NNTP) Extension for Streaming Feeds",
163.6153 -                 RFC 4644, October 2006.
163.6154 -
163.6155 -
163.6156 -
163.6157 -
163.6158 -
163.6159 -
163.6160 -Feather                     Standards Track                   [Page 110]
163.6161 -
163.6162 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6163 -
163.6164 -
163.6165 -   [NNTP-TLS]    Murchison, K., Vinocur, J., and C. Newman, "Using
163.6166 -                 Transport Layer Security (TLS) with Network News
163.6167 -                 Transfer Protocol (NNTP)", RFC 4642, October 2006.
163.6168 -
163.6169 -   [RFC1036]     Horton, M. and R. Adams, "Standard for interchange of
163.6170 -                 USENET messages", RFC 1036, December 1987.
163.6171 -
163.6172 -   [RFC1305]     Mills, D., "Network Time Protocol (Version 3)
163.6173 -                 Specification, Implementation and Analysis", RFC 1305,
163.6174 -                 March 1992.
163.6175 -
163.6176 -   [RFC1869]     Klensin, J., Freed, N., Rose, M., Stefferud, E., and D.
163.6177 -                 Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
163.6178 -                 November 1995.
163.6179 -
163.6180 -   [RFC2616]     Fielding,  R., Gettys, J., Mogul, J., Frystyk, H.,
163.6181 -                 Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
163.6182 -                 Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
163.6183 -
163.6184 -   [RFC2629]     Rose, M., "Writing I-Ds and RFCs using XML", RFC 2629,
163.6185 -                 June 1999.
163.6186 -
163.6187 -   [RFC2822]     Resnick, P., "Internet Message Format", RFC 2822, April
163.6188 -                 2001.
163.6189 -
163.6190 -   [RFC2980]     Barber, S., "Common NNTP Extensions", RFC 2980, October
163.6191 -                 2000.
163.6192 -
163.6193 -   [ROBE1995]    Robertson, R., "FAQ: Overview database / NOV General
163.6194 -                 Information", January 1995.
163.6195 -
163.6196 -                 There is no definitive copy of this document known to
163.6197 -                 the author.  It was previously posted as the Usenet
163.6198 -                 article <news:nov-faq-1-930909720@agate.Berkeley.EDU>
163.6199 -
163.6200 -   [SALZ1992]    Salz, R., "Manual Page for wildmat(3) from the INN 1.4
163.6201 -                 distribution, Revision 1.10", April 1992.
163.6202 -
163.6203 -                 There is no definitive copy of this document known to
163.6204 -                 the author.
163.6205 -
163.6206 -
163.6207 -
163.6208 -
163.6209 -
163.6210 -
163.6211 -
163.6212 -
163.6213 -
163.6214 -
163.6215 -
163.6216 -Feather                     Standards Track                   [Page 111]
163.6217 -
163.6218 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6219 -
163.6220 -
163.6221 -Appendix A.  Interaction with Other Specifications
163.6222 -
163.6223 -   NNTP is most often used for transferring articles that conform to
163.6224 -   RFC 1036 [RFC1036] (such articles are called "Netnews articles"
163.6225 -   here).  It is also sometimes used for transferring email messages
163.6226 -   that conform to RFC 2822 [RFC2822] (such articles are called "email
163.6227 -   articles" here).  In this situation, articles must conform both to
163.6228 -   this specification and to that other one; this appendix describes
163.6229 -   some relevant issues.
163.6230 -
163.6231 -A.1.  Header Folding
163.6232 -
163.6233 -   NNTP allows a header line to be folded (by inserting a CRLF pair)
163.6234 -   before any space or TAB character.
163.6235 -
163.6236 -   Both email and Netnews articles are required to have at least one
163.6237 -   octet other than space or TAB on each header line.  Thus, folding can
163.6238 -   only happen at one point in each sequence of consecutive spaces or
163.6239 -   TABs.  Netnews articles are further required to have the header name,
163.6240 -   colon, and following space all on the first line; folding may only
163.6241 -   happen beyond that space.  Finally, some non-conforming software will
163.6242 -   remove trailing spaces and TABs from a line.  Therefore, it might be
163.6243 -   inadvisable to fold a header after a space or TAB.
163.6244 -
163.6245 -   For maximum safety, header lines SHOULD conform to the following
163.6246 -   syntax rather than to that in Section 9.7.
163.6247 -
163.6248 -
163.6249 -     header = header-name ":" SP [header-content] CRLF
163.6250 -     header-content = [WS] token *( [CRLF] WS token )
163.6251 -
163.6252 -A.2.  Message-IDs
163.6253 -
163.6254 -   Every article handled by an NNTP server MUST have a unique
163.6255 -   message-id.  For the purposes of this specification, a message-id is
163.6256 -   an arbitrary opaque string that merely needs to meet certain
163.6257 -   syntactic requirements and is just a way to refer to the article.
163.6258 -
163.6259 -   Because there is a significant risk that old articles will be
163.6260 -   reinjected into the global Usenet system, RFC 1036 [RFC1036] requires
163.6261 -   that message-ids are globally unique for all time.
163.6262 -
163.6263 -   This specification states that message-ids are the same if and only
163.6264 -   if they consist of the same sequence of octets.  Other specifications
163.6265 -   may define two different sequences as being equal because they are
163.6266 -   putting an interpretation on particular characters.  RFC 2822
163.6267 -   [RFC2822] has a concept of "quoted" and "escaped" characters.  It
163.6268 -   therefore considers the three message-ids:
163.6269 -
163.6270 -
163.6271 -
163.6272 -Feather                     Standards Track                   [Page 112]
163.6273 -
163.6274 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6275 -
163.6276 -
163.6277 -      <ab.cd@example.com>
163.6278 -      <"ab.cd"@example.com>
163.6279 -      <"ab.\cd"@example.com>
163.6280 -
163.6281 -   as being identical.  Therefore, an NNTP implementation handing email
163.6282 -   articles must ensure that only one of these three appears in the
163.6283 -   protocol and that the other two are converted to it as and when
163.6284 -   necessary, such as when a client checks the results of a NEWNEWS
163.6285 -   command against an internal database of message-ids.  Note that
163.6286 -   RFC 1036 [RFC1036] never treats two different strings as being
163.6287 -   identical.  Its successor (as of the time of writing) restricts the
163.6288 -   syntax of message-ids so that, whenever RFC 2822 would treat two
163.6289 -   strings as equivalent, only one of them is valid (in the above
163.6290 -   example, only the first string is valid).
163.6291 -
163.6292 -   This specification does not describe how the message-id of an article
163.6293 -   is determined; it may be deduced from the contents of the article or
163.6294 -   derived from some external source.  If the server is also conforming
163.6295 -   to another specification that contains a definition of message-id
163.6296 -   compatible with this one, the server SHOULD use those message-ids.  A
163.6297 -   common approach, and one that SHOULD be used for email and Netnews
163.6298 -   articles, is to extract the message-id from the contents of a header
163.6299 -   with name "Message-ID".  This may not be as simple as copying the
163.6300 -   entire header contents; it may be necessary to strip off comments and
163.6301 -   undo quoting, or to reduce "equivalent" message-ids to a canonical
163.6302 -   form.
163.6303 -
163.6304 -   If an article is obtained through the IHAVE command, there will be a
163.6305 -   message-id provided with the command.  The server MAY either use it
163.6306 -   or determine one from the article contents.  However, whichever it
163.6307 -   does, it SHOULD ensure that, if the IHAVE command is repeated with
163.6308 -   the same argument and article, it will be recognized as a duplicate.
163.6309 -
163.6310 -   If an article does not contain a message-id that the server can
163.6311 -   identify, it MUST synthesize one.  This could, for example, be a
163.6312 -   simple sequence number or be based on the date and time when the
163.6313 -   article arrived.  When email or Netnews articles are handled, a
163.6314 -   Message-ID header SHOULD be added to ensure global consistency and
163.6315 -   uniqueness.
163.6316 -
163.6317 -   Note that, because the message-id might not have been derived from
163.6318 -   the Message-ID header in the article, the following example is
163.6319 -   legitimate (though unusual):
163.6320 -
163.6321 -
163.6322 -
163.6323 -
163.6324 -
163.6325 -
163.6326 -
163.6327 -
163.6328 -Feather                     Standards Track                   [Page 113]
163.6329 -
163.6330 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6331 -
163.6332 -
163.6333 -      [C] HEAD <45223423@example.com>
163.6334 -      [S] 221 0 <45223423@example.com>
163.6335 -      [S] Path: pathost!demo!whitehouse!not-for-mail
163.6336 -      [S] Message-ID: <1234@example.net>
163.6337 -      [S] From: "Demo User" <nobody@example.net>
163.6338 -      [S] Newsgroups: misc.test
163.6339 -      [S] Subject: I am just a test article
163.6340 -      [S] Date: 6 Oct 1998 04:38:40 -0500
163.6341 -      [S] Organization: An Example Net, Uncertain, Texas
163.6342 -      [S] .
163.6343 -
163.6344 -A.3.  Article Posting
163.6345 -
163.6346 -   As far as NNTP is concerned, the POST and IHAVE commands provide the
163.6347 -   same basic facilities in a slightly different way.  However, they
163.6348 -   have rather different intentions.
163.6349 -
163.6350 -   The IHAVE command is intended for transmitting conforming articles
163.6351 -   between a system of NNTP servers, with all articles perhaps also
163.6352 -   conforming to another specification (e.g., all articles are Netnews
163.6353 -   articles).  It is expected that the client will already have done any
163.6354 -   necessary validation (or that it has in turn obtained the article
163.6355 -   from a third party that has done so); therefore, the contents SHOULD
163.6356 -   be left unchanged.
163.6357 -
163.6358 -   In contrast, the POST command is intended for use when an end-user is
163.6359 -   injecting a newly created article into a such a system.  The article
163.6360 -   being transferred might not be a conforming email or Netnews article,
163.6361 -   and the server is expected to validate it and, if necessary, to
163.6362 -   convert it to the right form for onward distribution.  This is often
163.6363 -   done by a separate piece of software on the server installation; if
163.6364 -   so, the NNTP server SHOULD pass the incoming article to that software
163.6365 -   unaltered, making no attempt to filter characters, to fold or limit
163.6366 -   lines, or to process the incoming text otherwise.
163.6367 -
163.6368 -   The POST command can fail in various ways, and clients should be
163.6369 -   prepared to re-send an article.  When doing so, however, it is often
163.6370 -   important to ensure (as far as possible) that the same message-id is
163.6371 -   allocated to both attempts so that the server, or other servers, can
163.6372 -   recognize the two articles as duplicates.  In the case of email or
163.6373 -   Netnews articles, therefore, the posted article SHOULD contain a
163.6374 -   header with the name "Message-ID", and the contents of this header
163.6375 -   SHOULD be identical on each attempt.  The server SHOULD ensure that
163.6376 -   two POSTed articles with the same contents for this header are
163.6377 -   recognized as identical and that the same message-id is allocated,
163.6378 -   whether or not those contents are suitable for use as the message-id.
163.6379 -
163.6380 -
163.6381 -
163.6382 -
163.6383 -
163.6384 -Feather                     Standards Track                   [Page 114]
163.6385 -
163.6386 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6387 -
163.6388 -
163.6389 -Appendix B.  Summary of Commands
163.6390 -
163.6391 -   This section contains a list of every command defined in this
163.6392 -   document, ordered by command name and by indicating capability.
163.6393 -
163.6394 -                         Ordered by command name:
163.6395 -
163.6396 -       +-------------------+-----------------------+---------------+
163.6397 -       | Command           | Indicating capability | Definition    |
163.6398 -       +-------------------+-----------------------+---------------+
163.6399 -       | ARTICLE           | READER                | Section 6.2.1 |
163.6400 -       | BODY              | READER                | Section 6.2.3 |
163.6401 -       | CAPABILITIES      | mandatory             | Section 5.2   |
163.6402 -       | DATE              | READER                | Section 7.1   |
163.6403 -       | GROUP             | READER                | Section 6.1.1 |
163.6404 -       | HDR               | HDR                   | Section 8.5   |
163.6405 -       | HEAD              | mandatory             | Section 6.2.2 |
163.6406 -       | HELP              | mandatory             | Section 7.2   |
163.6407 -       | IHAVE             | IHAVE                 | Section 6.3.2 |
163.6408 -       | LAST              | READER                | Section 6.1.3 |
163.6409 -       | LIST              | LIST                  | Section 7.6.1 |
163.6410 -       | LIST ACTIVE.TIMES | LIST                  | Section 7.6.4 |
163.6411 -       | LIST ACTIVE       | LIST                  | Section 7.6.3 |
163.6412 -       | LIST DISTRIB.PATS | LIST                  | Section 7.6.5 |
163.6413 -       | LIST HEADERS      | HDR                   | Section 8.6   |
163.6414 -       | LIST NEWSGROUPS   | LIST                  | Section 7.6.6 |
163.6415 -       | LIST OVERVIEW.FMT | OVER                  | Section 8.4   |
163.6416 -       | LISTGROUP         | READER                | Section 6.1.2 |
163.6417 -       | MODE READER       | MODE-READER           | Section 5.3   |
163.6418 -       | NEWGROUPS         | READER                | Section 7.3   |
163.6419 -       | NEWNEWS           | NEWNEWS               | Section 7.4   |
163.6420 -       | NEXT              | READER                | Section 6.1.4 |
163.6421 -       | OVER              | OVER                  | Section 8.3   |
163.6422 -       | POST              | POST                  | Section 6.3.1 |
163.6423 -       | QUIT              | mandatory             | Section 5.4   |
163.6424 -       | STAT              | mandatory             | Section 6.2.4 |
163.6425 -       +-------------------+-----------------------+---------------+
163.6426 -
163.6427 -
163.6428 -
163.6429 -
163.6430 -
163.6431 -
163.6432 -
163.6433 -
163.6434 -
163.6435 -
163.6436 -
163.6437 -
163.6438 -
163.6439 -
163.6440 -Feather                     Standards Track                   [Page 115]
163.6441 -
163.6442 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6443 -
163.6444 -
163.6445 -                     Ordered by indicating capability:
163.6446 -
163.6447 -       +-------------------+-----------------------+---------------+
163.6448 -       | Command           | Indicating capability | Definition    |
163.6449 -       +-------------------+-----------------------+---------------+
163.6450 -       | CAPABILITIES      | mandatory             | Section 5.2   |
163.6451 -       | HEAD              | mandatory             | Section 6.2.2 |
163.6452 -       | HELP              | mandatory             | Section 7.2   |
163.6453 -       | QUIT              | mandatory             | Section 5.4   |
163.6454 -       | STAT              | mandatory             | Section 6.2.4 |
163.6455 -       | HDR               | HDR                   | Section 8.5   |
163.6456 -       | LIST HEADERS      | HDR                   | Section 8.6   |
163.6457 -       | IHAVE             | IHAVE                 | Section 6.3.2 |
163.6458 -       | LIST              | LIST                  | Section 7.6.1 |
163.6459 -       | LIST ACTIVE       | LIST                  | Section 7.6.3 |
163.6460 -       | LIST ACTIVE.TIMES | LIST                  | Section 7.6.4 |
163.6461 -       | LIST DISTRIB.PATS | LIST                  | Section 7.6.5 |
163.6462 -       | LIST NEWSGROUPS   | LIST                  | Section 7.6.6 |
163.6463 -       | MODE READER       | MODE-READER           | Section 5.3   |
163.6464 -       | NEWNEWS           | NEWNEWS               | Section 7.4   |
163.6465 -       | OVER              | OVER                  | Section 8.3   |
163.6466 -       | LIST OVERVIEW.FMT | OVER                  | Section 8.4   |
163.6467 -       | POST              | POST                  | Section 6.3.1 |
163.6468 -       | ARTICLE           | READER                | Section 6.2.1 |
163.6469 -       | BODY              | READER                | Section 6.2.3 |
163.6470 -       | DATE              | READER                | Section 7.1   |
163.6471 -       | GROUP             | READER                | Section 6.1.1 |
163.6472 -       | LAST              | READER                | Section 6.1.3 |
163.6473 -       | LISTGROUP         | READER                | Section 6.1.2 |
163.6474 -       | NEWGROUPS         | READER                | Section 7.3   |
163.6475 -       | NEXT              | READER                | Section 6.1.4 |
163.6476 -       +-------------------+-----------------------+---------------+
163.6477 -
163.6478 -
163.6479 -
163.6480 -
163.6481 -
163.6482 -
163.6483 -
163.6484 -
163.6485 -
163.6486 -
163.6487 -
163.6488 -
163.6489 -
163.6490 -
163.6491 -
163.6492 -
163.6493 -
163.6494 -
163.6495 -
163.6496 -Feather                     Standards Track                   [Page 116]
163.6497 -
163.6498 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6499 -
163.6500 -
163.6501 -Appendix C.  Summary of Response Codes
163.6502 -
163.6503 -   This section contains a list of every response code defined in this
163.6504 -   document and indicates whether it is multi-line, which commands can
163.6505 -   generate it, what arguments it has, and what its meaning is.
163.6506 -
163.6507 -   Response code 100 (multi-line)
163.6508 -      Generated by: HELP
163.6509 -      Meaning: help text follows.
163.6510 -
163.6511 -   Response code 101 (multi-line)
163.6512 -      Generated by: CAPABILITIES
163.6513 -      Meaning: capabilities list follows.
163.6514 -
163.6515 -   Response code 111
163.6516 -      Generated by: DATE
163.6517 -      1 argument: yyyymmddhhmmss
163.6518 -      Meaning: server date and time.
163.6519 -
163.6520 -   Response code 200
163.6521 -      Generated by: initial connection, MODE READER
163.6522 -      Meaning: service available, posting allowed.
163.6523 -
163.6524 -   Response code 201
163.6525 -      Generated by: initial connection, MODE READER
163.6526 -      Meaning: service available, posting prohibited.
163.6527 -
163.6528 -   Response code 205
163.6529 -      Generated by: QUIT
163.6530 -      Meaning: connection closing (the server immediately closes the
163.6531 -      connection).
163.6532 -
163.6533 -   Response code 211
163.6534 -      The 211 response code has two completely different forms,
163.6535 -      depending on which command generated it:
163.6536 -
163.6537 -         (not multi-line)
163.6538 -         Generated by: GROUP
163.6539 -         4 arguments: number low high group
163.6540 -         Meaning: group selected.
163.6541 -
163.6542 -         (multi-line)
163.6543 -         Generated by: LISTGROUP
163.6544 -         4 arguments: number low high group
163.6545 -         Meaning: article numbers follow.
163.6546 -
163.6547 -
163.6548 -
163.6549 -
163.6550 -
163.6551 -
163.6552 -Feather                     Standards Track                   [Page 117]
163.6553 -
163.6554 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6555 -
163.6556 -
163.6557 -   Response code 215 (multi-line)
163.6558 -      Generated by: LIST
163.6559 -      Meaning: information follows.
163.6560 -
163.6561 -   Response code 220 (multi-line)
163.6562 -      Generated by: ARTICLE
163.6563 -      2 arguments: n message-id
163.6564 -      Meaning: article follows.
163.6565 -
163.6566 -   Response code 221 (multi-line)
163.6567 -      Generated by: HEAD
163.6568 -      2 arguments: n message-id
163.6569 -      Meaning: article headers follow.
163.6570 -
163.6571 -   Response code 222 (multi-line)
163.6572 -      Generated by: BODY
163.6573 -      2 arguments: n message-id
163.6574 -      Meaning: article body follows.
163.6575 -
163.6576 -   Response code 223
163.6577 -      Generated by: LAST, NEXT, STAT
163.6578 -      2 arguments: n message-id
163.6579 -      Meaning: article exists and selected.
163.6580 -
163.6581 -   Response code 224 (multi-line)
163.6582 -      Generated by: OVER
163.6583 -      Meaning: overview information follows.
163.6584 -
163.6585 -   Response code 225 (multi-line)
163.6586 -      Generated by: HDR
163.6587 -      Meaning: headers follow.
163.6588 -
163.6589 -   Response code 230 (multi-line)
163.6590 -      Generated by: NEWNEWS
163.6591 -      Meaning: list of new articles follows.
163.6592 -
163.6593 -   Response code 231 (multi-line)
163.6594 -      Generated by: NEWGROUPS
163.6595 -      Meaning: list of new newsgroups follows.
163.6596 -
163.6597 -   Response code 235
163.6598 -      Generated by: IHAVE (second stage)
163.6599 -      Meaning: article transferred OK.
163.6600 -
163.6601 -   Response code 240
163.6602 -      Generated by: POST (second stage)
163.6603 -      Meaning: article received OK.
163.6604 -
163.6605 -
163.6606 -
163.6607 -
163.6608 -Feather                     Standards Track                   [Page 118]
163.6609 -
163.6610 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6611 -
163.6612 -
163.6613 -   Response code 335
163.6614 -      Generated by: IHAVE (first stage)
163.6615 -      Meaning: send article to be transferred.
163.6616 -
163.6617 -   Response code 340
163.6618 -      Generated by: POST (first stage)
163.6619 -      Meaning: send article to be posted.
163.6620 -
163.6621 -   Response code 400
163.6622 -      Generic response and generated by initial connection
163.6623 -      Meaning: service not available or no longer available (the server
163.6624 -      immediately closes the connection).
163.6625 -
163.6626 -   Response code 401
163.6627 -      Generic response
163.6628 -      1 argument: capability-label
163.6629 -      Meaning: the server is in the wrong mode; the indicated capability
163.6630 -      should be used to change the mode.
163.6631 -
163.6632 -   Response code 403
163.6633 -      Generic response
163.6634 -      Meaning: internal fault or problem preventing action being taken.
163.6635 -
163.6636 -   Response code 411
163.6637 -      Generated by: GROUP, LISTGROUP
163.6638 -      Meaning: no such newsgroup.
163.6639 -
163.6640 -   Response code 412
163.6641 -      Generated by: ARTICLE, BODY, GROUP, HDR, HEAD, LAST, LISTGROUP,
163.6642 -      NEXT, OVER, STAT
163.6643 -      Meaning: no newsgroup selected.
163.6644 -
163.6645 -   Response code 420
163.6646 -      Generated by: ARTICLE, BODY, HDR, HEAD, LAST, NEXT, OVER, STAT
163.6647 -      Meaning: current article number is invalid.
163.6648 -
163.6649 -   Response code 421
163.6650 -      Generated by: NEXT
163.6651 -      Meaning: no next article in this group.
163.6652 -
163.6653 -   Response code 422
163.6654 -      Generated by: LAST
163.6655 -      Meaning: no previous article in this group.
163.6656 -
163.6657 -   Response code 423
163.6658 -      Generated by: ARTICLE, BODY, HDR, HEAD, OVER, STAT
163.6659 -      Meaning: no article with that number or in that range.
163.6660 -
163.6661 -
163.6662 -
163.6663 -
163.6664 -Feather                     Standards Track                   [Page 119]
163.6665 -
163.6666 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6667 -
163.6668 -
163.6669 -   Response code 430
163.6670 -      Generated by: ARTICLE, BODY, HDR, HEAD, OVER, STAT
163.6671 -      Meaning: no article with that message-id.
163.6672 -
163.6673 -   Response code 435
163.6674 -      Generated by: IHAVE (first stage)
163.6675 -      Meaning: article not wanted.
163.6676 -
163.6677 -   Response code 436
163.6678 -      Generated by: IHAVE (either stage)
163.6679 -      Meaning: transfer not possible (first stage) or failed (second
163.6680 -      stage); try again later.
163.6681 -
163.6682 -   Response code 437
163.6683 -      Generated by: IHAVE (second stage)
163.6684 -      Meaning: transfer rejected; do not retry.
163.6685 -
163.6686 -   Response code 440
163.6687 -      Generated by: POST (first stage)
163.6688 -      Meaning: posting not permitted.
163.6689 -
163.6690 -   Response code 441
163.6691 -      Generated by: POST (second stage)
163.6692 -      Meaning: posting failed.
163.6693 -
163.6694 -   Response code 480
163.6695 -      Generic response
163.6696 -      Meaning: command unavailable until the client has authenticated
163.6697 -      itself.
163.6698 -
163.6699 -   Response code 483
163.6700 -      Generic response
163.6701 -      Meaning: command unavailable until suitable privacy has been
163.6702 -      arranged.
163.6703 -
163.6704 -   Response code 500
163.6705 -      Generic response
163.6706 -      Meaning: unknown command.
163.6707 -
163.6708 -   Response code 501
163.6709 -      Generic response
163.6710 -      Meaning: syntax error in command.
163.6711 -
163.6712 -
163.6713 -
163.6714 -
163.6715 -
163.6716 -
163.6717 -
163.6718 -
163.6719 -
163.6720 -Feather                     Standards Track                   [Page 120]
163.6721 -
163.6722 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6723 -
163.6724 -
163.6725 -   Response code 502
163.6726 -      Generic response and generated by initial connection
163.6727 -
163.6728 -      Meaning for the initial connection and the MODE READER command:
163.6729 -      service permanently unavailable (the server immediately closes the
163.6730 -      connection).
163.6731 -
163.6732 -      Meaning for all other commands: command not permitted (and there
163.6733 -      is no way for the client to change this).
163.6734 -
163.6735 -   Response code 503
163.6736 -      Generic response
163.6737 -      Meaning: feature not supported.
163.6738 -
163.6739 -   Response code 504
163.6740 -      Generic response
163.6741 -      Meaning: error in base64-encoding [RFC4648] of an argument.
163.6742 -
163.6743 -Appendix D.  Changes from RFC 977
163.6744 -
163.6745 -   In general every attempt has been made to ensure that the protocol
163.6746 -   specification in this document is compatible with the version
163.6747 -   specified in RFC 977 [RFC977] and the various facilities adopted from
163.6748 -   RFC 2980 [RFC2980].  However, there have been a number of changes,
163.6749 -   some compatible and some not.
163.6750 -
163.6751 -   This appendix lists these changes.  It is not guaranteed to be
163.6752 -   exhaustive or correct and MUST NOT be relied on.
163.6753 -
163.6754 -   o  A formal syntax specification (Section 9) has been added.
163.6755 -
163.6756 -   o  The default character set is changed from US-ASCII [ANSI1986] to
163.6757 -      UTF-8 [RFC3629] (note that US-ASCII is a subset of UTF-8).  This
163.6758 -      matter is discussed further in Section 10.
163.6759 -
163.6760 -   o  All articles are required to have a message-id, eliminating the
163.6761 -      "<0>" placeholder used in RFC 977 in some responses.
163.6762 -
163.6763 -   o  The newsgroup name matching capabilities already documented in
163.6764 -      RFC 977 ("wildmats", Section 4) are clarified and extended.  The
163.6765 -      new facilities (e.g., the use of commas and exclamation marks) are
163.6766 -      allowed wherever wildmats appear in the protocol.
163.6767 -
163.6768 -   o  Support for pipelining of commands (Section 3.5) is made
163.6769 -      mandatory.
163.6770 -
163.6771 -
163.6772 -
163.6773 -
163.6774 -
163.6775 -
163.6776 -Feather                     Standards Track                   [Page 121]
163.6777 -
163.6778 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6779 -
163.6780 -
163.6781 -   o  The principles behind response codes (Section 3.2) have been
163.6782 -      tidied up.  In particular:
163.6783 -
163.6784 -      *  the x8x response code family, formerly used for private
163.6785 -         extensions, is now reserved for authentication and privacy
163.6786 -         extensions;
163.6787 -
163.6788 -      *  the x9x response code family, formerly intended for debugging
163.6789 -         facilities, are now reserved for private extensions;
163.6790 -
163.6791 -      *  the 502 and 503 generic response codes (Section 3.2.1) have
163.6792 -         been redefined;
163.6793 -
163.6794 -      *  new 401, 403, 480, 483, and 504 generic response codes have
163.6795 -         been added.
163.6796 -
163.6797 -   o  The rules for article numbering (Section 6) have been clarified
163.6798 -      (also see Section 6.1.1.2).
163.6799 -
163.6800 -   o  The SLAVE command (which was ill-defined) is removed from the
163.6801 -      protocol.
163.6802 -
163.6803 -   o  Four-digit years are permitted in the NEWNEWS (Section 7.4) and
163.6804 -      NEWGROUPS (Section 7.3) commands (two-digit years are still
163.6805 -      permitted).  The optional distribution parameter to these commands
163.6806 -      has been removed.
163.6807 -
163.6808 -   o  The LIST command (Section 7.6.1) is greatly extended; the original
163.6809 -      is available as LIST ACTIVE, while new variants include
163.6810 -      ACTIVE.TIMES, DISTRIB.PATS, and NEWSGROUPS.  A new "m" status flag
163.6811 -      is added to the LIST ACTIVE response.
163.6812 -
163.6813 -   o  A new CAPABILITIES command (Section 5.2) allows clients to
163.6814 -      determine what facilities are supported by a server.
163.6815 -
163.6816 -   o  The DATE command (Section 7.1) is adopted from RFC 2980
163.6817 -      effectively unchanged.
163.6818 -
163.6819 -   o  The LISTGROUP command (Section 6.1.2) is adopted from RFC 2980.
163.6820 -      An optional range argument has been added, and the 211 initial
163.6821 -      response line now has the same format as the 211 response from the
163.6822 -      GROUP command.
163.6823 -
163.6824 -   o  The MODE READER command (Section 5.3) is adopted from RFC 2980 and
163.6825 -      its meaning and effects clarified.
163.6826 -
163.6827 -   o  The XHDR command in RFC 2980 has been formalised as the new HDR
163.6828 -      (Section 8.5) and LIST HEADERS (Section 8.6) commands.
163.6829 -
163.6830 -
163.6831 -
163.6832 -Feather                     Standards Track                   [Page 122]
163.6833 -
163.6834 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6835 -
163.6836 -
163.6837 -   o  The XOVER command in RFC 2980 has been formalised as the new OVER
163.6838 -      (Section 8.3) and LIST OVERVIEW.FMT (Section 8.4) commands.  The
163.6839 -      former can be applied to a message-id as well as to a range.
163.6840 -
163.6841 -   o  The concept of article metadata (Section 8.1) has been formalised,
163.6842 -      allowing the Bytes and Lines pseudo-headers to be deprecated.
163.6843 -
163.6844 -   Client authors should note in particular that lack of support for the
163.6845 -   CAPABILITIES command is a good indication that the server does not
163.6846 -   support this specification.
163.6847 -
163.6848 -
163.6849 -
163.6850 -
163.6851 -
163.6852 -
163.6853 -
163.6854 -
163.6855 -
163.6856 -
163.6857 -
163.6858 -
163.6859 -
163.6860 -
163.6861 -
163.6862 -
163.6863 -
163.6864 -
163.6865 -
163.6866 -
163.6867 -
163.6868 -
163.6869 -
163.6870 -
163.6871 -
163.6872 -
163.6873 -
163.6874 -
163.6875 -
163.6876 -
163.6877 -
163.6878 -
163.6879 -
163.6880 -
163.6881 -
163.6882 -
163.6883 -
163.6884 -
163.6885 -
163.6886 -
163.6887 -
163.6888 -Feather                     Standards Track                   [Page 123]
163.6889 -
163.6890 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6891 -
163.6892 -
163.6893 -Author's Address
163.6894 -
163.6895 -   Clive D.W. Feather
163.6896 -   THUS plc
163.6897 -   322 Regents Park Road
163.6898 -   London
163.6899 -   N3  2QQ
163.6900 -   United Kingdom
163.6901 -
163.6902 -   Phone: +44 20 8495 6138
163.6903 -   Fax:   +44 870 051 9937
163.6904 -   EMail: clive@demon.net
163.6905 -   URI:   http://www.davros.org/
163.6906 -
163.6907 -
163.6908 -
163.6909 -
163.6910 -
163.6911 -
163.6912 -
163.6913 -
163.6914 -
163.6915 -
163.6916 -
163.6917 -
163.6918 -
163.6919 -
163.6920 -
163.6921 -
163.6922 -
163.6923 -
163.6924 -
163.6925 -
163.6926 -
163.6927 -
163.6928 -
163.6929 -
163.6930 -
163.6931 -
163.6932 -
163.6933 -
163.6934 -
163.6935 -
163.6936 -
163.6937 -
163.6938 -
163.6939 -
163.6940 -
163.6941 -
163.6942 -
163.6943 -
163.6944 -Feather                     Standards Track                   [Page 124]
163.6945 -
163.6946 -RFC 3977         Network News Transfer Protocol (NNTP)      October 2006
163.6947 -
163.6948 -
163.6949 -Full Copyright Statement
163.6950 -
163.6951 -Copyright (C) The Internet Society (2006).
163.6952 -
163.6953 -   This document is subject to the rights, licenses and restrictions
163.6954 -   contained in BCP 78, and except as set forth therein, the authors
163.6955 -   retain all their rights.
163.6956 -
163.6957 -   This document and the information contained herein are provided on an
163.6958 -   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
163.6959 -   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
163.6960 -   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
163.6961 -   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
163.6962 -   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
163.6963 -   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
163.6964 -
163.6965 -Intellectual Property
163.6966 -
163.6967 -   The IETF takes no position regarding the validity or scope of any
163.6968 -   Intellectual Property Rights or other rights that might be claimed to
163.6969 -   pertain to the implementation or use of the technology described in
163.6970 -   this document or the extent to which any license under such rights
163.6971 -   might or might not be available; nor does it represent that it has
163.6972 -   made any independent effort to identify any such rights.  Information
163.6973 -   on the procedures with respect to rights in RFC documents can be
163.6974 -   found in BCP 78 and BCP 79.
163.6975 -
163.6976 -   Copies of IPR disclosures made to the IETF Secretariat and any
163.6977 -   assurances of licenses to be made available, or the result of an
163.6978 -   attempt made to obtain a general license or permission for the use of
163.6979 -   such proprietary rights by implementers or users of this
163.6980 -   specification can be obtained from the IETF on-line IPR repository at
163.6981 -   http://www.ietf.org/ipr.
163.6982 -
163.6983 -   The IETF invites any interested party to bring to its attention any
163.6984 -   copyrights, patents or patent applications, or other proprietary
163.6985 -   rights that may cover technology that may be required to implement
163.6986 -   this standard.  Please address the information to the IETF at ietf-
163.6987 -   ipr@ietf.org.
163.6988 -
163.6989 -Acknowledgement
163.6990 -
163.6991 -   Funding for the RFC Editor function is provided by the IETF
163.6992 -   Administrative Support Activity (IASA).
163.6993 -
163.6994 -
163.6995 -
163.6996 -
163.6997 -
163.6998 -
163.6999 -
163.7000 -Feather                     Standards Track                   [Page 125]
163.7001 -
   164.1 --- a/trunk/test/StringTemplateTest.java	Tue Jan 20 10:21:03 2009 +0100
   164.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   164.3 @@ -1,26 +0,0 @@
   164.4 -/*
   164.5 - * To change this template, choose Tools | Templates
   164.6 - * and open the template in the editor.
   164.7 - */
   164.8 -
   164.9 -package test;
  164.10 -
  164.11 -import com.so.news.util.StringTemplate;
  164.12 -
  164.13 -/**
  164.14 - *
  164.15 - * @author chris
  164.16 - */
  164.17 -public class StringTemplateTest 
  164.18 -{
  164.19 -  public static void main(String[] args)
  164.20 -  {
  164.21 -    StringTemplate templ 
  164.22 -      = new StringTemplate("SELECT %row FROM %table WHERE %row = ich");
  164.23 -    
  164.24 -    templ.set("row", "name");
  164.25 -    templ.set("table", "UserTable");
  164.26 -    
  164.27 -    System.out.println(templ.toString());
  164.28 -  }
  164.29 -}