// Host Update // // Douglas Thrift // // $Id$ #include "HostUpdate.hpp" #include "Host.hpp" #ifndef _WIN32 #include #else #include #endif int main(int argc, char* argv[]) { #ifndef _WIN32 ::res_init(); for (short index(0); index < MAXNS; ++index) if (index + 1 < MAXNS) ::memcpy(&_res.nsaddr_list[index].sin_addr, &_res.nsaddr_list[index + 1].sin_addr, sizeof(in_addr_t)); else ::memset(&_res.nsaddr_list[index].sin_addr, 0, sizeof(in_addr_t)); ::umask(0111); #endif HostUpdate update; return 0; } HostUpdate::HostUpdate() : host(false), name(false), address(false), platform(false), since(false) { { struct ::stat hosts; if (::stat("hosts", &hosts) != 0) ::mkdir("hosts"); } std::string agent = sgetenv("HTTP_USER_AGENT"); std::string method = sgetenv("REQUEST_METHOD"); parse(method); mode(); if (agent.find("Host Update/") == 0 && method == "POST" && agent.find(" (") != std::string::npos && agent.find(") libwww-perl/") != std::string::npos) update(agent); else if (agent.find("Host Update Sharp/") == 0 && method == "POST" && agent.find(" (") != std::string::npos && agent.find(')') != std::string::npos) update(agent); else display(); } void HostUpdate::parse(const std::string& method) { std::string query; if (method == "POST") std::getline(std::cin, query); else query = sgetenv("QUERY_STRING"); if (query.empty()) return; std::istringstream input(query); do { std::string name, value; std::getline(input, name, '='); std::getline(input, value, '&'); cgi.insert(std::pair(name, value)); } while (input.good()); } void HostUpdate::mode() { for (std::multimap::iterator itor(cgi.find("mode")); itor != cgi.upper_bound("mode") && itor != cgi.end(); itor++) { std::string mode(itor->second); for (std::string::iterator itor(mode.begin()); itor != mode.end(); itor++) { char mode(*itor); switch (mode) { case 'h': if (!host) host = true; break; case 'n': if (!name) name = true; break; case 'a': if (!address) address = true; break; case 'p': if (!platform) platform = true; break; case 's': if (!since) since = true; break; } } } if (!host && !name && !address && !platform && !since) host = true, name = true, address = true, platform = true, since = true; } void HostUpdate::update(const std::string& agent) { std::cout << "Content-Type: text/plain\n\n"; std::multimap::iterator itor = cgi.find("host"); if (itor == cgi.end()) return; if (itor->second.empty()) return; std::string host(itor->second), name(sgetenv("REMOTE_HOST")), address(sgetenv("REMOTE_ADDR")); std::string::size_type begin(agent.find('(') + 1), end(agent.rfind(')')); if (begin >= end) return; std::string platform(agent.substr(begin, end - begin)); Host client(host, name, address, platform), saved(host); if (client != ++saved) client--; display(client); } void HostUpdate::display() { std::cout << "Content-Type: text/plain\n\n"; { bool request(false); for (std::multimap::iterator itor(cgi.find("host")); itor != cgi.upper_bound("host") && itor != cgi.end(); itor++) { if (!itor->second.empty()) { Host host(itor->second); display(++host); if (!request) request = true; } } if (request) return; } std::set hosts; #ifndef _WIN32 DIR* ::dir(opendir("hosts")); struct ::dirent* ent; while ((ent = ::readdir(dir)) != NULL) { std::string file(ent->d_name); if (file.empty() || file[0] == '.') continue; Host host(file); hosts.insert(++host); } ::closedir(dir); #else WIN32_FIND_DATA found; HANDLE find(::FindFirstFile("hosts\\*", &found)); do { std::string file(found.cFileName); if (file.empty() || file[0] == '.') continue; Host host(file); hosts.insert(++host); } while (::FindNextFile(find, &found) != 0); ::FindClose(find); #endif for (std::set::iterator itor(hosts.begin()); itor != hosts.end(); itor++) display(*itor); } void HostUpdate::display(const Host& host) { if (this->host) std::cout << "host=" << host.getHost() << '\n'; if (name) std::cout << "name=" << host.getName() << '\n'; if (address) std::cout << "address=" << host.getAddress() << '\n'; if (platform) std::cout << "platform=" << host.getPlatform() << '\n'; std::string name(std::string("hosts") + slash + host.getHost()); struct ::stat file; if (since && ::stat(name.c_str(), &file) == 0) { char since[20]; ::strftime(since, 20, "%m/%d/%Y %H:%M:%S", ::gmtime(&file.st_mtime)); std::cout << "since=" << since << " GMT\n"; } else if (since) { char since[20]; time_t now(::time(NULL)); ::strftime(since, 20, "%m/%d/%Y %H:%M:%S", ::gmtime(&now)); std::cout << "since=" << since << " GMT\n"; } }