00001
00002 #include <fstream>
00003 #include <sstream>
00004 #include <stdexcept>
00005 #include <ctype.h>
00006 #include <dvutil/props.h>
00007 #include <dvutil/tostring.h>
00008 #include <dvutil/file.h>
00009 #include <dvutil/logstream.h>
00010
00011 #include "index.h"
00012 #include "query.h"
00013 #include "server.h"
00014
00015 using namespace Dv;
00016
00017
00018
00019
00020 istream&
00021 getmaxline(istream& is, string& line, string::size_type max_size) {
00022 if (is) {
00023 char* buf = new char[max_size+2];
00024 is.getline(buf,max_size+1,'\n');
00025 line = buf;
00026 delete buf;
00027 }
00028 return is;
00029 }
00030
00031 Server::Server(const string& conf_fn) throw (runtime_error):
00032 config_fn_(conf_fn), max_cmd_(2048), log_(0) {
00033 ifstream ifs(config_fn().c_str());
00034 if (!ifs)
00035 throw runtime_error(config_fn() + ": cannot open");
00036 Util::Props config(ifs);
00037
00038 port_ = config["portnr"];
00039 index_fn_ = config["index"];
00040 wordlength_ = config["wordlength"];
00041 ignore_fn_ = config["ignore"];
00042 log_fn_ = config["logfile"];
00043 if (config("maxcmd"))
00044 max_cmd_ = config["maxcmd"];
00045
00046 log_ = new Dv::Util::logstream(log_fn(), index_fn() );
00047 if (!*log_)
00048 throw runtime_error(log_fn() + ": cannot open");
00049
00050
00051 index_ = new Index(wordlength());
00052
00053
00054 ifstream ignore_is(ignore_fn().c_str());
00055 if (!ignore_is)
00056 throw runtime_error(ignore_fn() + ": cannot open");
00057 index().ignore(ignore_is);
00058
00059
00060 ifstream index_is(index_fn().c_str());
00061 if (index_is)
00062 index_is >> index();
00063 }
00064
00065 Server::~Server() {
00066 delete log_;
00067 delete index_;
00068 }
00069
00070 bool
00071 Server::ok_to_index(const string& path, ostream& err) const {
00072 try {
00073 Util::File f(path);
00074 f.expand();
00075
00076 if (!f.exists()) {
00077 err << error() << path << ": does not exist";
00078 return false;
00079 }
00080 if (f.type() != Util::File::REGULAR) {
00081 err << error() << path << ": not a regular file";
00082 return false;
00083 }
00084 ifstream ifs(path.c_str());
00085 if (!ifs) {
00086 err << error() << path << ": cannot open for reading";
00087 return false;
00088 }
00089 for (size_t i=0; (i<100); ++i) {
00090 char c(ifs.get());
00091 if (c==EOF)
00092 break;
00093 if (isprint(c) || isspace(c)) {
00094 }
00095 else {
00096 err << error() << path << ": not a text file";
00097 return false;
00098 }
00099 }
00100 }
00101 catch (...) {
00102 return false;
00103 }
00104 return true;
00105 }
00106
00107
00108 bool
00109 Server::serve(iostream& ios) {
00110 string line;
00111 while (getmaxline(ios, line, max_cmd())) {
00112 if (line.size() > max_cmd() ) {
00113 log() << error() << "command too long, max = " << max_cmd() << endl;
00114 return true;
00115 }
00116
00117 if (line.size() == 0) {
00118 log() << error() << "empty command" << endl;
00119 return true;
00120 }
00121
00122 log() << "CMD: " << line << endl;
00123
00124 istringstream iss(line);
00125
00126 string command;
00127 iss >> command;
00128
00129 if (command == "stop") {
00130 log() << "STOP" << endl;
00131 ios << ok() << endl;
00132 return false;
00133 }
00134 else if (command == "save") {
00135 log() << "SAVE" << endl;
00136 ofstream index_os(index_fn().c_str());
00137 if (index_os) {
00138 index_os << index();
00139 index_os.close();
00140 log() << ok() << endl;
00141 ios << ok() << endl;
00142 }
00143 else {
00144 log() << "ERROR SAVING" << endl;
00145 ios << error() << "cannot save to \"" << index_fn() << "\"" << endl;
00146 }
00147 }
00148 else if (command == "add") {
00149 string path;
00150 iss >> path;
00151 ostringstream oss;
00152 if (ok_to_index(path, oss)) {
00153 Util::File f(path);
00154 path = f.expand().str();
00155
00156 time_t ti(index().date(path));
00157 time_t tn(f.last_modified());
00158 if (tn>ti) {
00159 ifstream ifs(f.path());
00160 index().insert(f.str(),ifs);
00161 }
00162 log() << ok() << endl;
00163 ios << ok() << endl;
00164 }
00165 else {
00166 log() << oss.str() << endl;
00167 ios << oss.str() << endl;
00168 }
00169 }
00170 else if (command == "query") {
00171 string qs;
00172 getline(iss,qs);
00173 log() << "QUERY " << qs << endl;
00174 try {
00175 Query q(index(), qs);
00176 const Index::Files& r(q.exec());
00177 log() << "ANSWER: " << r.size() << " FILES" << endl;
00178 for (Index::Files::const_iterator f=r.begin(); f!=r.end(); ++f)
00179 ios << **f << endl;
00180
00181 ios << endl;
00182 }
00183 catch (exception& e) {
00184 log() << error() << e.what() << endl;
00185 }
00186 }
00187 else {
00188 ios << error() << "unknown command: \"" << command << "\"" << endl;
00189 log() << error() << "unknown command: \"" << command << "\"" << endl;
00190 }
00191 }
00192 return true;
00193 }
00194