1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2004-2006, 2008, 2011, 2012 Peter Miller
4 //
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; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18
19 #include <common/ac/assert.h>
20 #include <common/ac/stdlib.h>
21
22 #include <common/symtab.h>
23 #include <libaegis/input/crop.h>
24 #include <libaegis/input/stdin.h>
25 #include <libaegis/os.h>
26 #include <libaegis/output/file.h>
27 #include <libaegis/output/filter/prefix.h>
28 #include <libaegis/output/stdout.h>
29 #include <libaegis/output/tee.h>
30
31 #include <aecvsserver/file_info.h>
32 #include <aecvsserver/net.h>
33 #include <aecvsserver/response.h>
34
35
net_ty()36 net_ty::net_ty() :
37 in(new input_stdin()),
38 out(output_stdout::create()),
39 rooted(0),
40 response_queue_length(0),
41 response_queue_max(0),
42 response_queue_item(0),
43 dir_info_cs(0),
44 dir_info_ss(0),
45 curdir(0),
46 file_info(0)
47 {
48 //
49 // Initialize which responses the client is capable of receiving.
50 //
51 for (int j = 0; j < response_code_MAX; ++j)
52 response_valid[j] = 0;
53 response_valid[response_code_E] = 1;
54 response_valid[response_code_error] = 1;
55 response_valid[response_code_hate] = 1;
56 response_valid[response_code_love] = 1;
57 response_valid[response_code_ok] = 1;
58 response_valid[response_code_Valid_requests] = 1;
59
60 //
61 // Set SO_KEEPALIVE on the socket, so that we don't hang forever
62 // if the client dies while we are waiting for input.
63 //
64 in->keepalive();
65 }
66
67
~net_ty()68 net_ty::~net_ty()
69 {
70 out.reset();
71
72 if (updating_verbose)
73 {
74 str_free(updating_verbose);
75 updating_verbose = 0;
76 }
77
78 log_client.reset();
79 if (dir_info_cs)
80 {
81 delete dir_info_cs;
82 dir_info_cs = 0;
83 }
84 if (dir_info_ss)
85 {
86 delete dir_info_ss;
87 dir_info_ss = 0;
88 }
89 curdir = 0;
90 if (file_info)
91 {
92 delete file_info;
93 file_info = 0;
94 }
95 }
96
97
98 bool
getline(nstring & s)99 net_ty::getline(nstring &s)
100 {
101 bool result = in->one_line(s);
102 if (result && log_client)
103 {
104 log_client->fprintf("%s\n", s.c_str());
105 log_client->flush();
106 }
107 return result;
108 }
109
110
111 void
printf(const char * fmt,...)112 net_ty::printf(const char *fmt, ...)
113 {
114 va_list ap;
115 assert(fmt);
116 va_start(ap, fmt);
117 out->vfprintf(fmt, ap);
118 va_end(ap);
119 }
120
121
122 void
response_queue(response * rp)123 net_ty::response_queue(response *rp)
124 {
125 //
126 // Don't bother queueing responses the client has asked us not to send.
127 //
128 response_code_ty code = rp->code_get();
129 if (!response_valid[code])
130 {
131 delete rp;
132 return;
133 }
134
135 //
136 // Make sure there is enough room in the queue.
137 //
138 if (response_queue_length >= response_queue_max)
139 {
140 response_queue_max = response_queue_max * 2 + 4;
141 response **new_queue = new response * [response_queue_max];
142 for (size_t k = 0; k < response_queue_length; ++k)
143 new_queue[k] = response_queue_item[k];
144 delete [] response_queue_item;
145 response_queue_item = new_queue;
146 }
147
148 //
149 // Put the response on the end of the queue.
150 //
151 response_queue_item[response_queue_length++] = rp;
152
153 //
154 // Some codes cause an immediate flush.
155 //
156 if (rp->flushable())
157 response_flush();
158 }
159
160
161 void
response_flush()162 net_ty::response_flush()
163 {
164 //
165 // Write any pending responses to the client.
166 //
167 for (size_t j = 0; j < response_queue_length; ++j)
168 {
169 response *rp;
170
171 rp = response_queue_item[j];
172 rp->write(out);
173 delete rp;
174 if (log_client)
175 out->flush();
176 }
177 response_queue_length = 0;
178
179 //
180 // Make sure the output is written to the client.
181 //
182 out->flush();
183 }
184
185
186 void
log_to_file(string_ty * filename)187 net_ty::log_to_file(string_ty *filename)
188 {
189 // This only works once
190 if (log_client)
191 return;
192
193 os_become_orig();
194 output::pointer op = output_file::text_open(filename);
195 os_become_undo();
196 log_client = output_filter_prefix::create(op, "C: ");
197 output::pointer log_server = output_filter_prefix::create(op, "S: ");
198 out = output_tee::create(out, log_server);
199 }
200
201
202 void
log_by_env(const char * envar)203 net_ty::log_by_env(const char *envar)
204 {
205 const char *cp = getenv(envar);
206 if (!cp || !*cp)
207 return;
208 string_ty *s = str_from_c(cp);
209 log_to_file(s);
210 str_free(s);
211 }
212
213
214 void
argument(string_ty * s)215 net_ty::argument(string_ty *s)
216 {
217 assert(s);
218 argument_list.push_back(s);
219 }
220
221
222 void
argumentx(string_ty * s)223 net_ty::argumentx(string_ty *s)
224 {
225 assert(s);
226 if (argument_list.nstrings)
227 {
228 static string_ty *newline;
229 string_ty **spp;
230 string_ty *s2;
231
232 if (!newline)
233 newline = str_from_c("\n");
234 spp = argument_list.string + argument_list.nstrings - 1;
235 s2 = str_cat_three(*spp, newline, s);
236 str_free(*spp);
237 *spp = s2;
238 }
239 else
240 argument_list.push_back(s);
241 }
242
243
244 void
accumulator_reset()245 net_ty::accumulator_reset()
246 {
247 argument_list.clear();
248 if (file_info)
249 file_info->clear();
250 if (dir_info_cs)
251 dir_info_cs->clear();
252 if (dir_info_ss)
253 dir_info_ss->clear();
254 curdir = 0;
255 if (updating_verbose)
256 {
257 str_free(updating_verbose);
258 updating_verbose = 0;
259 }
260 }
261
262
263 static void
file_info_reaper(void * p)264 file_info_reaper(void *p)
265 {
266 file_info_delete((file_info_ty *)p);
267 }
268
269
270 file_info_ty *
file_info_find(string_ty * server_side,int auto_alloc)271 net_ty::file_info_find(string_ty *server_side, int auto_alloc)
272 {
273 file_info_ty *fip;
274
275 if (!file_info)
276 {
277 file_info = new symtab_ty(5);
278 file_info->set_reap(file_info_reaper);
279 }
280 fip = (file_info_ty *)file_info->query(server_side);
281 if (!fip && auto_alloc)
282 {
283 fip = file_info_new();
284 file_info->assign(server_side, fip);
285 }
286 return fip;
287 }
288
289
290 static void
dir_reaper(void * p)291 dir_reaper(void *p)
292 {
293 directory_ty *dp;
294
295 dp = (directory_ty *)p;
296 directory_delete(dp);
297 }
298
299
300 void
directory_set(string_ty * client_side,string_ty * server_side)301 net_ty::directory_set(string_ty *client_side, string_ty *server_side)
302 {
303 directory_ty *dp;
304
305 dp = directory_new(client_side, server_side);
306 curdir = dp;
307 if (!dir_info_cs)
308 {
309 dir_info_cs = new symtab_ty(5);
310 dir_info_cs->set_reap(dir_reaper);
311 }
312 dir_info_cs->assign(client_side, dp);
313 if (!dir_info_ss)
314 {
315 dir_info_ss = new symtab_ty(5);
316 // NO reaper for this one.
317 }
318 dir_info_ss->assign(server_side, dp);
319 }
320
321
322 directory_ty *
directory_find_client_side(string_ty * client_side)323 net_ty::directory_find_client_side(string_ty *client_side)
324 {
325 if (!dir_info_cs)
326 return 0;
327 return (directory_ty *)dir_info_cs->query(client_side);
328 }
329
330
331 directory_ty *
directory_find_server_side(string_ty * server_side)332 net_ty::directory_find_server_side(string_ty *server_side)
333 {
334 if (!dir_info_ss)
335 return 0;
336 return (directory_ty *)dir_info_ss->query(server_side);
337 }
338
339
340 void
set_updating_verbose(string_ty * s)341 net_ty::set_updating_verbose(string_ty *s)
342 {
343 if (updating_verbose)
344 {
345 str_free(updating_verbose);
346 updating_verbose = 0;
347 }
348 if (s)
349 updating_verbose = str_copy(s);
350 }
351
352
353 input
in_crop(long length)354 net_ty::in_crop(long length)
355 {
356 return new input_crop(in, length);
357 }
358
359
360 // vim: set ts=8 sw=4 et :
361