////////////////////////////////////////////////////////////////////// // isapicfg: HTML-based configuration dialog. #if 0 #include "wisapicfg.h" #include "version.h" #include ////////////////////////////////////////////////////////////////////// static const char title[] = "Konfigurace konektoru internetového serveru"; ////////////////////////////////////////////////////////////////////// class SHandle { public: SHandle(SC_HANDLE handle = 0) : handle(handle) {} ~SHandle() { if(handle) CloseServiceHandle(handle); } operator SC_HANDLE () const { return handle; } void Clear() { Attach(0); } SC_HANDLE Detach() { SC_HANDLE h = handle; handle = 0; return h; } void Attach(SC_HANDLE h) { if(handle) CloseServiceHandle(handle); handle = h; } SHandle& operator = (SC_HANDLE h) { Attach(h); return *this; } bool Query(SERVICE_STATUS& s) { return handle && QueryServiceStatus(handle, &s); } private: SC_HANDLE handle; }; ////////////////////////////////////////////////////////////////////// struct ServiceInfo { String display_name; String service_name; dword state; }; template class Moveable; ////////////////////////////////////////////////////////////////////// static Array EnumServices(SHandle& manager) { dword resume_handle = 0; dword more = 0; bool cont; Array list; do { dword done; union { ENUM_SERVICE_STATUS status[1]; char buffer[10000]; }; bool result = EnumServicesStatus(manager, SERVICE_WIN32, SERVICE_STATE_ALL, status, sizeof(buffer), &more, &done, &resume_handle); cont = (!result && GetLastError() == ERROR_MORE_DATA); if(!result && !cont) break; for(int i = 0; i < done; i++) { ServiceInfo& info = list.Add(); info.display_name = status[i].lpDisplayName; info.service_name = status[i].lpServiceName; info.state = status[i].ServiceStatus.dwCurrentState; } } while(cont); return list; } ////////////////////////////////////////////////////////////////////// static HtmlTag HtmlSimpleRow() { return HtmlRow() % HtmlCell().ColSpan(2).Width(-100); } ////////////////////////////////////////////////////////////////////// static Htmls HtmlSplitRow(const char *tag, const Htmls& content) { return HtmlRow() % (HtmlCell().Width(-30) / tag + "\n" + HtmlCell().Left().Width(-70) / content); } ////////////////////////////////////////////////////////////////////// static Htmls HtmlValueRow(const char *tag, const Value& value) { return HtmlSplitRow(tag, HtmlBold() / value.Format()); } ////////////////////////////////////////////////////////////////////// static Htmls HtmlMenu(bool active, const char *text, const char *url, int wd) { HtmlTag table = HtmlTable().CellSpacing(0).Border(2) .BorderColor(Black).BgColor(active ? Yellow : WhiteGray); if(wd) table.Width(wd); return table % HtmlRow() % HtmlCell().Center() / HtmlLink(url) / HtmlFontColor(Black) / (active ? HtmlBold() / text : Htmls(text)); } ////////////////////////////////////////////////////////////////////// static Htmls HtmlHardSpace(int count = 1) { StringBuffer s(count * 6); char *p = s; for(int i = 0; i < count; i++) { memcpy(p, " ", 6); p += 6; } return s; } ////////////////////////////////////////////////////////////////////// static HtmlTag HtmlIsapiTable() { return HtmlTable().Width(-70).CellSpacing(0).CellPadding(1).Border(1).BgColor(WhiteGray) % HtmlRow() % HtmlCell() % HtmlTable().Width(-100).CellSpacing(2).CellPadding(0).Border(0).BgColor(WhiteGray); } ////////////////////////////////////////////////////////////////////// IsapiCfg::IsapiCfg(IsapiClient& client, const char *url) : map(url) , client(client) , config_url(client.isapi_url + "?configure") , can_write(-1) { default_host << "localhost@" << DEFAULT_PORT; #ifdef _DEBUG for(int i = 0; i < map.GetCount(); i++) LOG("map[" << i << "] = (" << map.GetKey(i) << " / " << map[i]); #endif } ////////////////////////////////////////////////////////////////////// bool IsapiCfg::Run(String& header, String& content, String& error) { Htmls body = Body(); content = HtmlTag("HTML") % (HtmlTag("HEAD") % (HtmlTag("TITLE") / title) + HtmlTag("BODY").BgColor(White) % body); return true; } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Body() { Htmls body; body << HtmlTag("H1") / title << HtmlTag("SMALL") / "Umístění knihovny: " << HtmlTag("TT") / ToHtml(client.isapi_path) << "
\n" << HtmlTag("SMALL") / "Verze: " ISAPI_VERSION ", datum výroby: " ISAPI_DATE "
\n" ISAPI_COPYRIGHT "

\n"; String s = map.GetString(ID_CONFIGURE); enum { CONFIG, STAT /*, SERV */ } page = CONFIG; switch(*s) { case 's': page = STAT; break; // case 'r': page = SERV; break; } Htmls menu; menu << HtmlCell() / HtmlMenu(page == CONFIG, "Konfigurace", config_url, 120) << HtmlCell() / HtmlHardSpace(2) << HtmlCell() / HtmlMenu(page == STAT, "Statistika", config_url + "=s", 120) // << HtmlCell() / HtmlHardSpace(2) // << HtmlCell() / HtmlMenu(page == SERV, "Služby", config_url + "=r", 120) ; body << HtmlTable().CellSpacing(0) % HtmlRow() % menu << "

\n"; switch(page) { case CONFIG: body << Configuration(); break; case STAT: body << Statistics(); break; // case SERV: body << Services(); break; } return body; } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Configuration() { Htmls content; content << Login() << HtmlSimpleRow() << Timing() << HtmlSimpleRow() << Servers(); content // must be the last one as Timing() and Servers() might modify some client data << HtmlSimpleRow() << Commit(); if(!IsNull(error)) content = HtmlSimpleRow() / HtmlFontColor(LtRed) / (HtmlBig() / ("Chyba: " + HtmlBold() / error)) + HtmlSimpleRow() + content; return HtmlTag("FORM").Attr("METHOD", "POST").Attr("ACTION", config_url) % HtmlIsapiTable() % content; } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Timing() { Htmls s; s << HtmlSimpleRow() % HtmlBig() / "Časové konstanty" << HtmlSplitRow("Předání dotazu (s):", ~Edit(ID_QUERY_TIMEOUT, client.query_timeout)) << HtmlSplitRow("Výsledek dotazu (s):", ~Edit(ID_ANSWER_TIMEOUT, client.answer_timeout)); return s; } ////////////////////////////////////////////////////////////////////// HtmlTag IsapiCfg::Edit(Id id, int& value) { int vsec = value / 1000; int new_value = map.GetInt(id); if(!IsNull(new_value) && new_value != vsec) { if(new_value >= 1 && new_value <= 600) value = new_value * 1000; else error = "Hodnota je mimo povolený rozsah (1 - 600 s)."; } if(IsNull(new_value)) new_value = vsec; return HtmlEdit(id).Data(IntStr(new_value)).Size(6); } ////////////////////////////////////////////////////////////////////// static Htmls HtmlTableRow(const Htmls& host, const Htmls& state, const Htmls& modf, Color c) { Htmls cells; cells << HtmlCell().Width(-50) % host; if(!IsNull(modf)) cells << HtmlCell().Width(-10) % state << HtmlCell().Width(-40) % modf; else cells << HtmlCell().ColSpan(2).Width(-50) % state; return HtmlRow().BgColor(c) % cells; } ////////////////////////////////////////////////////////////////////// static const char no_gen[] = "V tuto chvíli nejsou připojeny žádné generátory."; static Htmls NoGenMsg() { return HtmlFontColor(LtBlue) / HtmlTag("I") / no_gen; } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Servers() { int count = map.GetInt(ID_HOSTCOUNT); if(!IsNull(count)) { for(int i = 0; i < count; i++) if(map.Find("RMHOST" + IntStr(i)) >= 0) { // remove this host String hostid = map.GetString("HOST" + IntStr(i)); if(CanWrite()) error = client.Remove(hostid); break; } } if(map.Find(ID_ADDHOST) >= 0 && CanWrite() && IsNull(error = client.Add(map.GetString(ID_NEW_HOST)))) { // advance current port number String s = map.GetString(ID_NEW_HOST); int i = s.Find('@'); int port = DEFAULT_PORT; if(i < 0) i = s.GetLength(); else { port = stou(s.Begin() + i + 1); if(port == -1) port = DEFAULT_PORT; } s.Trim(i); s << '@' << (port + 1); map.Set(ID_NEW_HOST, s); } Htmls table; table << HtmlTableRow(HtmlBold() / "Generátor", HtmlBold() / "Akt. stav", "", Yellow); // output connection parameters client.LockConnections(); count = client.GetCount(); table << HtmlHidden(ID_HOSTCOUNT, count) << "\n"; for(int i = 0; i < count; i++) { const IsapiClient::Connection& conn = client[i]; table << HtmlHidden("HOST" + IntStr(i), conn.GetHost()) << "\n"; String status; if(conn.IsBusy()) status = "pracuje"; else if(conn.IsError()) status = "chyba"; else status = "čeká"; String host = conn.GetHost(); table << HtmlTableRow(host, status, ~HtmlSubmit("Smazat").Name((const char *)("RMHOST" + IntStr(i))), White); } client.UnlockConnections(); Htmls new_host; new_host << "Přidat generátor: " << HtmlEdit(ID_NEW_HOST).Data(map(ID_NEW_HOST, default_host)) << " " << HtmlSubmit(" Vložit ").Name(ID_ADDHOST); Htmls s; s << HtmlSimpleRow() / HtmlBig() / "Aktivní generátory"; if(count > 0) s << HtmlSimpleRow() % (HtmlTable().CellSpacing(0).CellPadding(0) .BgColor(White).Border(0).Center().Width(-100) % table); else s << HtmlSimpleRow() / NoGenMsg(); s << HtmlSimpleRow() / new_host; return s; } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Login() { Htmls s; s << HtmlSimpleRow() / HtmlBig() / "Heslo pro zápis" << HtmlSplitRow("Heslo:", ~HtmlInput("PASSWORD").Name(ID_PASSWORD).Data(map(ID_PASSWORD, Null))); return s; } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Commit() { Htmls text; text << HtmlSimpleRow() << HtmlSimpleRow().Left() % HtmlSubmit("Zapsat konfiguraci").Name(ID_SAVE_CONFIG); if(map.Find(ID_SAVE_CONFIG) >= 0 && CanWrite()) if(client.Save()) text << HtmlSimpleRow() << HtmlSimpleRow() % HtmlFontColor(LtBlue) / HtmlBig() / "Konfigurační soubor byl korektně uložen."; else error = "Chyba při zápisu konfiguračního souboru."; return text; } ////////////////////////////////////////////////////////////////////// static Htmls HtmlStatGenRow(const Value& gen, const Value& num, const Value& avg, const Value& max, const Value& err, const HtmlTag& tag = HtmlTag()) { return Htmls() << HtmlCell().Width(-32) / tag / gen.Format() << HtmlCell().Width(-17) / tag / num.Format() << HtmlCell().Width(-17) / tag / avg.Format() << HtmlCell().Width(-17) / tag / max.Format() << HtmlCell().Width(-17) / tag / err.Format(); } ////////////////////////////////////////////////////////////////////// Htmls IsapiCfg::Statistics() { Htmls content; client.LockStatistics(); double duration = GetSysTime() - client.run_time; int id = fround(duration); String dd; if(id < 60) dd << id << " s"; else if(id < 60 * 60) dd << id / 60 << " min, " << id % 60 << " s"; else { int hours = ffloor(duration / 3600); id = fround(duration - 3600.0 * hours); dd << hours << " h, " << id / 60 << " min, " << id % 60 << " s"; } content << HtmlSimpleRow() % HtmlBig() / "Celková statistika" << HtmlValueRow("Spuštění serveru:", client.run_time) << HtmlValueRow("Doba běhu:", dd) << HtmlValueRow("Počet dotazů:", client.num_requests) << HtmlValueRow("Počet chyb:", client.num_errors) << HtmlValueRow("Průměrná odezva (ms):", client.total_ticks / max(client.num_requests - client.num_errors, 1)) << HtmlValueRow("Nejdelší odezva (ms):", client.max_ticks) << HtmlSimpleRow() << HtmlSimpleRow() % HtmlBig() / "Statistika po generátorech" << HtmlSimpleRow(); client.UnlockStatistics(); client.LockConnections(); int count = client.GetCount(); if(count == 0) content << HtmlSimpleRow() % NoGenMsg(); else { Htmls table; table << HtmlRow().BgColor(Yellow) % HtmlStatGenRow("Generátor", "Dotazy", "Odezva (ms)", "Max (ms)", "Chyby", HtmlBold()); for(int i = 0; i < count; i++) { IsapiClient::Connection& conn = client[i]; conn.Enter(); table << HtmlRow().BgColor(White) % HtmlStatGenRow(conn.GetHost(), conn.num_requests, conn.total_ticks / max(conn.num_requests - conn.num_errors, 1), conn.max_ticks, conn.num_errors); conn.Leave(); } content << HtmlSimpleRow() % HtmlTable().CellSpacing(0).CellPadding(0) .BgColor(White).Border(0).Center().Width(-100) % table; } client.UnlockConnections(); return HtmlIsapiTable() % content; } ////////////////////////////////////////////////////////////////////// bool IsapiCfg::CanWrite() { if(can_write < 0) { String pwd = CsToLower(map.GetString(ID_PASSWORD)); if(IsNull(pwd)) { can_write = 0; error = "Při zápisu změn musíte zadat platné heslo."; } else if(!(can_write = (pwd == CsToLower(client.admin_pwd)))) error = "Neplatné heslo; zkontrolujte nastavení klávesnice."; } return !!can_write; } ////////////////////////////////////////////////////////////////////// /* Htmls IsapiCfg::Services() { Htmls content; content << Login() << HtmlSimpleRow() % HtmlBig("Instalované služby") << HtmlSimpleRow() % ServiceTable(); if(!IsNull(error)) content = HtmlSimpleRow() / HtmlFontColor(LtRed) / (HtmlBig("Chyba: " + HtmlBold(error))) + HtmlSimpleRow() + content; return HtmlTag("FORM").Attr("METHOD", "POST").Attr("ACTION", config_url + "=r") % HtmlIsapiTable() % content; } */ ////////////////////////////////////////////////////////////////////// /* static Htmls HtmlServiceRow(Htmls cell1, Htmls cell2, Htmls cell3) { Htmls s; s << HtmlCell().Width(-50) / cell1 << HtmlCell().Width(-25) / cell2 << HtmlCell().Width(-25) / (cell3 + " "); return s; } */ ////////////////////////////////////////////////////////////////////// /* Htmls IsapiCfg::ServiceTable() { SHandle mgr = OpenSCManager(0, 0, GENERIC_READ | GENERIC_WRITE); if(!mgr) { error = "Přístup ke správci služeb byl odmítnut."; return Htmls(); } Array services = EnumServices(mgr); SortX(services, XField(&ServiceInfo::display_name), StdCsNumSort); Htmls table = HtmlRow().BgColor(Yellow) % HtmlServiceRow(HtmlBold("Název služby"), HtmlBold("Stav"), Null); for(int i = 0; i < services.GetCount(); i++) { const ServiceInfo& s = services[i]; const char *state = "(?)"; switch(s.state) { case SERVICE_START_PENDING: state = "spouští se"; break; case SERVICE_RUNNING: state = "běží"; break; case SERVICE_STOP_PENDING: state = "vypíná se"; break; case SERVICE_STOPPED: state = "vypnutá"; break; case SERVICE_CONTINUE_PENDING: state = "obnovuje se"; break; case SERVICE_PAUSE_PENDING: state = "pozastavuje se"; break; case SERVICE_PAUSED: state = "pozastavena"; break; } table << HtmlRow() % HtmlServiceRow(ToHtml(s.display_name), state, Null); } return HtmlTable().Width(-100).CellSpacing(0).CellPadding(0).Border(0).BgColor(White) % table; } */ ////////////////////////////////////////////////////////////////////// #endif