monotone

monotone Mtn Source Tree

Root/nntp_tasks.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include "transforms.hh"
7#include "network.hh"
8#include "nntp_tasks.hh"
9#include "proto_machine.hh"
10#include "sanity.hh"
11#include "ui.hh"
12
13#include <boost/tokenizer.hpp>
14#include <boost/lexical_cast.hpp>
15
16// this file contains simple functions which build up NNTP state
17// machines and run them using the infrastructure in proto_machine.{cc,hh}
18
19using namespace std;
20using boost::lexical_cast;
21using boost::tokenizer;
22using boost::char_separator;
23
24static void ws_split(string const & str, vector<string> & out)
25{
26 out.clear();
27 char_separator<char> whitespace("\r\n\t ");
28 tokenizer< char_separator<char> > tokens(str, whitespace);
29 copy(tokens.begin(), tokens.end(), back_inserter(out));
30}
31
32
33struct cursor_state : public cmd_state
34{
35 unsigned long & seq_number;
36 explicit cursor_state(string const & cmd, unsigned long & seq)
37 : cmd_state(cmd), seq_number(seq)
38 {}
39 virtual ~cursor_state() {}
40 virtual proto_edge drive(iostream & net, proto_edge const & e)
41 {
42 vector<string> response_args;
43 ws_split(e.msg, response_args);
44 if (response_args.size() > 1)
45 seq_number = lexical_cast<unsigned long>(response_args[1]);
46 return cmd_state::drive(net, e);
47 }
48};
49
50
51struct stat_state : public proto_state
52{
53 unsigned long & seq_number;
54 explicit stat_state(unsigned long & seq)
55 : seq_number(seq)
56 {}
57 virtual ~stat_state() {}
58 virtual proto_edge drive(iostream & net, proto_edge const & e)
59 {
60 vector<string> response_args;
61 vector<string> my_args;
62 unsigned long low = 0;
63 ws_split(e.msg, response_args);
64 if (response_args.size() > 2)
65 try
66{
67 low = lexical_cast<unsigned long>(response_args[2]);
68}
69 catch (...)
70{}
71 if (low > seq_number)
72 seq_number = low;
73 my_args.push_back(lexical_cast<string>(seq_number));
74 return proto_state::step_cmd(net, "STAT", my_args);
75 }
76};
77
78
79struct nntp_postlines_state : public proto_state
80{
81 string const & group;
82 string const & from;
83 string const & subject;
84 string const & body;
85 explicit nntp_postlines_state(string const & grp,
86string const & frm,
87string const & subj,
88string const & bod)
89 : group(grp), from(frm), subject(subj), body(bod)
90 {}
91 virtual ~nntp_postlines_state() {}
92 virtual proto_edge drive(iostream & net, proto_edge const & e)
93 {
94 vector<string> lines, split;
95 lines.push_back("From: " + from);
96 lines.push_back("Subject: " + subject);
97 lines.push_back("Newsgroups: " + group);
98 lines.push_back("");
99 split_into_lines(body, split);
100 copy(split.begin(), split.end(), back_inserter(lines));
101 return proto_state::step_lines(net, lines);
102 }
103};
104
105struct feedlines_state : public cmd_state
106{
107 ticker count;
108 packet_consumer & consumer;
109 explicit feedlines_state(packet_consumer & cons)
110 : cmd_state("NEXT"), count("packet"), consumer(cons)
111 {}
112 virtual ~feedlines_state() {}
113 virtual proto_edge drive(iostream & net, proto_edge const & e)
114 {
115 string joined;
116 join_lines(e.lines, joined);
117 stringstream ss(joined);
118 ++count;
119 read_packets(ss, consumer);
120 return cmd_state::drive(net, e);
121 }
122};
123
124
125bool post_nntp_article(string const & group_name,
126 string const & from,
127 string const & subject,
128 string const & article,
129 std::iostream & stream)
130{
131 // build state machine nodes
132 cmd_state mode_reader("MODE READER");
133 cmd_state post("POST");
134 nntp_postlines_state postlines(group_name, from, subject, article);
135 cmd_state quit("QUIT");
136
137 mode_reader.add_edge(200, &post); // posting ok
138 mode_reader.add_edge(201, &quit); // posting not ok
139
140 post.add_edge(340, &postlines); // ok, send lines
141 post.add_edge(440, &quit); // posting not allowed
142 post.add_edge(441, &quit); // posting failed
143
144 postlines.add_edge(240, &quit); // posting succeeded
145 postlines.add_edge(440, &quit); // posting not allowed
146 postlines.add_edge(441, &quit); // posting failed
147
148 run_proto_state_machine(&mode_reader, stream);
149 return (postlines.get_res_code() == 240);
150}
151
152
153void fetch_nntp_articles(string const & group_name,
154 unsigned long & seq_number,
155 packet_consumer & consumer,
156 std::iostream & stream)
157{
158
159 // build state machine nodes
160 cmd_state mode_reader("MODE READER");
161 cmd_state group("GROUP", group_name);
162 stat_state stat(seq_number);
163 cursor_state body("BODY", seq_number);
164 feedlines_state feeder(consumer);
165 cmd_state quit("QUIT");
166
167 // wire together edges
168 mode_reader.add_edge(200, &group); // posting ok
169 mode_reader.add_edge(201, &group); // posting not ok
170
171 group.add_edge(211, &stat); // group ok
172 group.add_edge(411, &quit); // no such newsgroup
173
174 stat.add_edge(223, &body); // stat ok -> body
175
176 body.add_edge(220, &feeder, true); // head and body ok -> next
177 body.add_edge(221, &feeder, true); // head ok -> next
178 body.add_edge(222, &feeder, true); // body ok -> next
179 body.add_edge(223, &body); // stat ok -> next
180
181 feeder.add_edge(223, &body); // next ok -> fetch body
182 feeder.add_edge(412, &quit); // no newsgroup
183 feeder.add_edge(420, &stat); // no current article
184 feeder.add_edge(421, &quit); // no more articles
185
186 body.add_edge(412, &group); // no newsgroup
187 body.add_edge(420, &stat); // no current article
188 body.add_edge(423, &quit); // no such article number
189 body.add_edge(430, &quit); // no such article
190
191 // run it
192 run_proto_state_machine(&mode_reader, stream);
193 P("nntp fetch complete\n");
194}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status