1 /* DigitalMars NNTP reader
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module chibackend
.net
.nntp
/*is aliced*/;
24 import chibackend
: DynStr
;
25 import chibackend
.net
.linesocket
;
34 auto nsk = new SocketNNTP(server);
35 scope(exit) nsk.close();
37 nsk.selectGroup(group);
39 conwriteln("[", name, ":", group, "]: no new articles");
43 uint stnum = inbox.maxNntpIndex+1;
44 if (stnum == 0) stnum = (nsk.hiwater > 1023 ? nsk.hiwater-1023 : 0);
45 if (stnum > nsk.hiwater) {
46 conwriteln("[", name, ":", group, "]: no new articles");
50 conwriteln("[", name, ":", group, "]: ", nsk.hiwater+1-stnum, " (possible) new articles");
52 // download new articles
53 foreach (immutable uint anum; stnum..nsk.hiwater+1) {
54 auto msg = nsk.getArticle(anum);
61 nsk = new SocketNNTP(server);
62 } catch (Exception e) {
63 conwriteln("[", name, ":", group, "]: connection error: ", e.msg);
66 scope(exit) nsk.close();
69 nsk.selectGroup(group);
71 nsk.doSendRaw(art.getTextToSend);
72 auto ln = nsk.readLine;
73 conwriteln(ln); // 340 Ok, recommended message-ID <o7dq4o$mpm$1@digitalmars.com>
74 if (ln.length == 0 || ln[0] != '3') throw new Exception(ln.idup);
75 } catch (Exception e) {
76 conwriteln("[", name, ":", group, "]: sending error: ", e.msg);
82 // ////////////////////////////////////////////////////////////////////////// //
83 public final class SocketNNTP
: SocketLine
{
87 public: //WARNING! DO NOT CHANGE!
89 uint lowater
, hiwater
;
90 bool emptyGroup
= true;
93 this (string server
, bool debugdump
=false) {
94 super(server
, plainport
:119, tlsport
:563, debugdump
:debugdump
);
95 scope(failure
) abort(doshutdown
:false);
96 auto hello
= readLine();
97 if (hello
.length
< 4 && hello
[0] != '2' || hello
[1] != '0' || hello
[3] != ' ') throw new Exception("invalid hello");
98 if (hello
[2] == '0') canPost
= true;
99 else if (hello
[2] == '1') canPost
= false;
100 else throw new Exception("invalid hello");
103 @property bool postingAllowed () const nothrow @safe @nogc { return canPost
; }
105 override void quit () {
108 auto ln
= readLine();
111 void selectGroup (const(char)[] name
) {
112 doSendCmdArg("GROUP", name
);
116 } catch (Throwable e
) {
117 abort(doshutdown
:false);
120 scope(failure
) { group
.clear(); lowater
= hiwater
= 0; emptyGroup
= true; }
122 if (getStrToken(ln
) != "211") {
123 conwriteln("*ERROR: NNTP server GROUP reply: ", origln
);
124 throw new Exception("invalid GROUP reply");
126 auto cnt
= getToken
!uint(ln
);
127 lowater
= getToken
!uint(ln
);
128 hiwater
= getToken
!uint(ln
);
129 if (cnt
== 0 || lowater
> hiwater ||
(lowater
== 0 && hiwater
== 0)) {
130 lowater
= hiwater
= 0;
138 // if `exact` is true, returns line with exact terminators
139 // returns empty string if there's no such article (this is not a error!)
140 // can return truncated message if it is too big
141 DynStr
getArticle(bool exact
=false) (uint num
) {
143 doSendCmdArg("ARTICLE", num
);
144 auto ln
= readLine();
145 //conwriteln("|", ln, "|");
146 auto rescode
= getToken
!uint(ln
);
147 if (rescode
!= 220) {
148 if (rescode
== 420 || rescode
== 423) {
149 //throw new Exception("no such article");
153 throw new Exception("ARTICLE failed");
155 if (getToken
!uint(ln
) != num
) { close(); throw new Exception("invalid replied article number"); }
157 //string msgid = getToken(ln).idup;
159 static if (exact
) bool needAddEOL
= false;
161 res
~= "NNTP-Index: ";
162 res
.appendNum(number
);
163 static if (exact
) needAddEOL
= true; else res
.append('\n');
164 if (mDebugDump
) conwriteln("+", number
);
171 if (needAddEOL
&& ln
.length
) {
172 if (ln
.length
>= 2 && ln
[$-2..$] == "\r\n") res
.append("\r\n"); else res
.append("\n");
178 static if (!exact
) res
~= '\n';
180 if (ln
.length
== 0 || ln
[0] != '.') continue;
181 if (ln
.length
== 1) break;
183 if (ln
.length
== 3 && ln
== ".\r\n") break;
184 if (ln
.length
== 2 && ln
== ".\n") break;
186 if (!toobig
&& res
.length
> 1024*1024*128) {
187 conwriteln("WARNING: mail message too big!");
192 if (needAddEOL
) res
.append('\n');