//
// aegis - project change supervisor
// Copyright (C) 2004-2006, 2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include // for assert
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
net_ty::net_ty() :
in(new input_stdin()),
out(output_stdout::create()),
rooted(0),
response_queue_length(0),
response_queue_max(0),
response_queue_item(0),
dir_info_cs(0),
dir_info_ss(0),
curdir(0),
file_info(0)
{
//
// Initialize which responses the client is capable of receiving.
//
for (int j = 0; j < response_code_MAX; ++j)
response_valid[j] = 0;
response_valid[response_code_E] = 1;
response_valid[response_code_error] = 1;
response_valid[response_code_hate] = 1;
response_valid[response_code_love] = 1;
response_valid[response_code_ok] = 1;
response_valid[response_code_Valid_requests] = 1;
//
// Set SO_KEEPALIVE on the socket, so that we don't hang forever
// if the client dies while we are waiting for input.
//
in->keepalive();
}
net_ty::~net_ty()
{
out.reset();
if (updating_verbose)
{
str_free(updating_verbose);
updating_verbose = 0;
}
log_client.reset();
if (dir_info_cs)
{
delete dir_info_cs;
dir_info_cs = 0;
}
if (dir_info_ss)
{
delete dir_info_ss;
dir_info_ss = 0;
}
curdir = 0;
if (file_info)
{
delete file_info;
file_info = 0;
}
}
bool
net_ty::getline(nstring &s)
{
bool result = in->one_line(s);
if (result && log_client)
{
log_client->fprintf("%s\n", s.c_str());
log_client->flush();
}
return result;
}
void
net_ty::printf(const char *fmt, ...)
{
va_list ap;
assert(fmt);
va_start(ap, fmt);
out->vfprintf(fmt, ap);
va_end(ap);
}
void
net_ty::response_queue(response *rp)
{
//
// Don't bother queueing responses the client has asked us not to send.
//
response_code_ty code = rp->code_get();
if (!response_valid[code])
{
delete rp;
return;
}
//
// Make sure there is enough room in the queue.
//
if (response_queue_length >= response_queue_max)
{
response_queue_max = response_queue_max * 2 + 4;
response **new_queue = new response * [response_queue_max];
for (size_t k = 0; k < response_queue_length; ++k)
new_queue[k] = response_queue_item[k];
delete [] response_queue_item;
response_queue_item = new_queue;
}
//
// Put the response on the end of the queue.
//
response_queue_item[response_queue_length++] = rp;
//
// Some codes cause an immediate flush.
//
if (rp->flushable())
response_flush();
}
void
net_ty::response_flush()
{
//
// Write any pending responses to the client.
//
for (size_t j = 0; j < response_queue_length; ++j)
{
response *rp;
rp = response_queue_item[j];
rp->write(out);
delete rp;
if (log_client)
out->flush();
}
response_queue_length = 0;
//
// Make sure the output is written to the client.
//
out->flush();
}
void
net_ty::log_to_file(string_ty *filename)
{
// This only works once
if (log_client)
return;
os_become_orig();
output::pointer op = output_file::text_open(filename);
os_become_undo();
log_client = output_prefix::create(op, "C: ");
output::pointer log_server = output_prefix::create(op, "S: ");
out = output_tee::create(out, log_server);
}
void
net_ty::log_by_env(const char *envar)
{
const char *cp = getenv(envar);
if (!cp || !*cp)
return;
string_ty *s = str_from_c(cp);
log_to_file(s);
str_free(s);
}
void
net_ty::argument(string_ty *s)
{
assert(s);
argument_list.push_back(s);
}
void
net_ty::argumentx(string_ty *s)
{
assert(s);
if (argument_list.nstrings)
{
static string_ty *newline;
string_ty **spp;
string_ty *s2;
if (!newline)
newline = str_from_c("\n");
spp = argument_list.string + argument_list.nstrings - 1;
s2 = str_cat_three(*spp, newline, s);
str_free(*spp);
*spp = s2;
}
else
argument_list.push_back(s);
}
void
net_ty::accumulator_reset()
{
argument_list.clear();
if (file_info)
file_info->clear();
if (dir_info_cs)
dir_info_cs->clear();
if (dir_info_ss)
dir_info_ss->clear();
curdir = 0;
if (updating_verbose)
{
str_free(updating_verbose);
updating_verbose = 0;
}
}
static void
file_info_reaper(void *p)
{
file_info_delete((file_info_ty *)p);
}
file_info_ty *
net_ty::file_info_find(string_ty *server_side, int auto_alloc)
{
file_info_ty *fip;
if (!file_info)
{
file_info = new symtab_ty(5);
file_info->set_reap(file_info_reaper);
}
fip = (file_info_ty *)file_info->query(server_side);
if (!fip && auto_alloc)
{
fip = file_info_new();
file_info->assign(server_side, fip);
}
return fip;
}
static void
dir_reaper(void *p)
{
directory_ty *dp;
dp = (directory_ty *)p;
directory_delete(dp);
}
void
net_ty::directory_set(string_ty *client_side, string_ty *server_side)
{
directory_ty *dp;
dp = directory_new(client_side, server_side);
curdir = dp;
if (!dir_info_cs)
{
dir_info_cs = new symtab_ty(5);
dir_info_cs->set_reap(dir_reaper);
}
dir_info_cs->assign(client_side, dp);
if (!dir_info_ss)
{
dir_info_ss = new symtab_ty(5);
// NO reaper for this one.
}
dir_info_ss->assign(server_side, dp);
}
directory_ty *
net_ty::directory_find_client_side(string_ty *client_side)
{
if (!dir_info_cs)
return 0;
return (directory_ty *)dir_info_cs->query(client_side);
}
directory_ty *
net_ty::directory_find_server_side(string_ty *server_side)
{
if (!dir_info_ss)
return 0;
return (directory_ty *)dir_info_ss->query(server_side);
}
void
net_ty::set_updating_verbose(string_ty *s)
{
if (updating_verbose)
{
str_free(updating_verbose);
updating_verbose = 0;
}
if (s)
updating_verbose = str_copy(s);
}
input
net_ty::in_crop(long length)
{
return new input_crop(in, length);
}