|
reSIProcate/repro
9694
|
00001 #include <cassert> 00002 #include <time.h> 00003 00004 #if defined(HAVE_CONFIG_H) 00005 #include "config.h" 00006 #endif 00007 00008 #include "resip/dum/RegistrationPersistenceManager.hxx" 00009 #include "resip/stack/Symbols.hxx" 00010 #include "resip/stack/Tuple.hxx" 00011 #include "resip/stack/SipStack.hxx" 00012 #include "rutil/Data.hxx" 00013 #include "rutil/DnsUtil.hxx" 00014 #include "rutil/Logger.hxx" 00015 #include "rutil/MD5Stream.hxx" 00016 #include "rutil/ParseBuffer.hxx" 00017 #include "rutil/Socket.hxx" 00018 #include "rutil/Timer.hxx" 00019 #include "rutil/TransportType.hxx" 00020 00021 #include "repro/ReproVersion.hxx" 00022 #include "repro/Proxy.hxx" 00023 #include "repro/HttpBase.hxx" 00024 #include "repro/HttpConnection.hxx" 00025 #include "repro/WebAdmin.hxx" 00026 #include "repro/RouteStore.hxx" 00027 #include "repro/UserStore.hxx" 00028 #include "repro/FilterStore.hxx" 00029 #include "repro/Store.hxx" 00030 00031 #ifdef USE_SSL 00032 #include "resip/stack/ssl/Security.hxx" 00033 #endif 00034 00035 using namespace resip; 00036 using namespace repro; 00037 using namespace std; 00038 00039 #define RESIPROCATE_SUBSYSTEM Subsystem::REPRO 00040 00041 #define REPRO_BORDERLESS_TABLE_PROPS " border=\"0\" cellspacing=\"2\" cellpadding=\"0\"" 00042 #define REPRO_BORDERED_TABLE_PROPS " border=\"1\" cellspacing=\"1\" cellpadding=\"1\" bgcolor=\"#ffffff\"" 00043 00044 WebAdmin::RemoveKey::RemoveKey(const Data &key1, const Data &key2) : mKey1(key1), mKey2(key2) 00045 { 00046 }; 00047 00048 bool 00049 WebAdmin::RemoveKey::operator<(const RemoveKey& rhs) const 00050 { 00051 if(mKey1 < rhs.mKey1) 00052 { 00053 return true; 00054 } 00055 else if(mKey1 == rhs.mKey1 && mKey2 < rhs.mKey2) 00056 { 00057 return true; 00058 } 00059 else 00060 { 00061 return false; 00062 } 00063 } 00064 00065 WebAdmin::WebAdmin( Proxy& proxy, 00066 RegistrationPersistenceManager& regDb, 00067 const Data& realm, // this realm is used for http challenges 00068 int port, 00069 IpVersion version ): 00070 HttpBase( port, version, realm ), 00071 mProxy(proxy), 00072 mStore(*mProxy.getConfig().getDataStore()), 00073 mRegDb(regDb), 00074 mNoWebChallenges(proxy.getConfig().getConfigBool("DisableHttpAuth", false)), 00075 mPageOutlinePre( 00076 #include "repro/webadmin/pageOutlinePre.ixx" 00077 ), 00078 mPageOutlinePost( 00079 #include "repro/webadmin/pageOutlinePost.ixx" 00080 ) 00081 { 00082 const Data adminName("admin"); 00083 const Data adminPassword= proxy.getConfig().getConfigData("HttpAdminPassword", "admin"); 00084 00085 // Place repro version into PageOutlinePre 00086 mPageOutlinePre.replace("VERSION", VersionUtils::instance().releaseVersion().c_str()); 00087 00088 Data dbA1 = mStore.mUserStore.getUserAuthInfo( adminName, Data::Empty ); 00089 00090 DebugLog(<< " Looking to see if admin user exists (creating WebAdmin)"); 00091 if ( dbA1.empty() ) // if the admin user does not exist, add it 00092 { 00093 DebugLog(<< "Creating admin user" ); 00094 00095 mStore.mUserStore.addUser( adminName, // user 00096 Data::Empty, // domain 00097 Data::Empty, // realm 00098 (adminPassword==""?Data("admin"):adminPassword), // password 00099 true, // applyA1HashToPassword 00100 Data::Empty, // name 00101 Data::Empty ); // email 00102 dbA1 = mStore.mUserStore.getUserAuthInfo( adminName, Data::Empty ); 00103 assert( !dbA1.empty() ); 00104 } 00105 else if (adminPassword!=Data("")) 00106 { 00107 //All we're using for admin is the password. 00108 //This next bit of code relies on it being ok that we 00109 //blow away any other information 00110 //in that row. It also expects addUser to replace anything matching the existing key 00111 DebugLog(<< "Changing the web admin password" ); 00112 mStore.mUserStore.addUser( adminName, 00113 Data::Empty, 00114 Data::Empty, 00115 adminPassword, 00116 true, // applyA1HashToPassword 00117 Data::Empty, 00118 Data::Empty); 00119 } 00120 } 00121 00122 00123 void 00124 WebAdmin::buildPage( const Data& uri, 00125 int pageNumber, 00126 const resip::Data& pUser, 00127 const resip::Data& pPassword ) 00128 { 00129 ParseBuffer pb(uri); 00130 00131 DebugLog (<< "Parsing URL" << uri ); 00132 00133 const char* anchor = pb.skipChar('/'); 00134 pb.skipToChar('?'); 00135 Data pageName; 00136 pb.data(pageName,anchor); 00137 00138 DebugLog (<< " got page name: " << pageName ); 00139 00140 // if this is not a valid page, redirect it 00141 if ( 00142 ( pageName != Data("index.html") ) && 00143 ( pageName != Data("input") ) && 00144 ( pageName != Data("cert.cer") ) && 00145 ( ! pageName.prefix("cert") ) && 00146 ( pageName != Data("userTest.html") ) && 00147 ( pageName != Data("domains.html") ) && 00148 ( pageName != Data("acls.html") ) && 00149 ( pageName != Data("addUser.html") ) && 00150 ( pageName != Data("editUser.html") ) && 00151 ( pageName != Data("showUsers.html") ) && 00152 ( pageName != Data("addFilter.html") ) && 00153 ( pageName != Data("editFilter.html") ) && 00154 ( pageName != Data("showFilters.html") )&& 00155 ( pageName != Data("addRoute.html") ) && 00156 ( pageName != Data("editRoute.html") ) && 00157 ( pageName != Data("showRoutes.html") )&& 00158 ( pageName != Data("registrations.html") ) && 00159 ( pageName != Data("settings.html") ) && 00160 ( pageName != Data("user.html") ) ) 00161 { 00162 setPage( resip::Data::Empty, pageNumber, 301 ); 00163 return; 00164 } 00165 00166 // pages anyone can use 00167 if ( pageName == Data("index.html") ) 00168 { 00169 setPage( buildDefaultPage(), pageNumber, 200); 00170 return; 00171 } 00172 00173 // certificate pages 00174 if ( pageName.prefix("cert") || pageName == Data("cert.cer") ) 00175 { 00176 #ifdef USE_SSL 00177 Data domain = mRealm; 00178 try 00179 { 00180 const char* anchor = pb.skipChar('?'); 00181 pb.skipToChar('='); 00182 Data query; 00183 pb.data(query, anchor); 00184 InfoLog( << "query is " << query ); 00185 if ( query == "domain" ) 00186 { 00187 anchor = pb.skipChar('='); 00188 pb.skipToEnd(); 00189 pb.data(domain, anchor); 00190 } 00191 } 00192 catch (ParseException& ) 00193 { 00194 } 00195 00196 if ( !domain.empty() ) 00197 { 00198 InfoLog( << "domain is " << domain ); 00199 try 00200 { 00201 setPage( buildCertPage(domain), pageNumber, 200, Mime("application","pkix-cert") ); 00202 } 00203 catch(BaseSecurity::Exception&) 00204 { 00205 setPage( resip::Data::Empty, pageNumber, 404 ); 00206 } 00207 return; 00208 } 00209 else 00210 { 00211 setPage( resip::Data::Empty, pageNumber, 404 ); 00212 return; 00213 } 00214 #else 00215 // ?bwc? Probably could use a better indication? 00216 setPage(resip::Data::Empty, pageNumber, 404); 00217 #endif 00218 } 00219 00220 Data authenticatedUser; 00221 if (mNoWebChallenges) 00222 { 00223 // do't do authentication - give everyone admin privilages 00224 authenticatedUser = Data("admin"); 00225 } 00226 else 00227 { 00228 // TODO !cj! - this code is broken - the user name in the web digest should be 00229 // moved to alice@example.com instead of alice and assuming the realm is 00230 // empty 00231 00232 // all pages after this, user must authenticate 00233 if ( pUser.empty() ) 00234 { 00235 setPage( resip::Data::Empty, pageNumber,401 ); 00236 return; 00237 } 00238 00239 // check that authentication is correct 00240 Data dbA1 = mStore.mUserStore.getUserAuthInfo( pUser, Data::Empty ); 00241 00242 #if 0 00243 if ( dbA1.empty() ) // if the admin user does not exist, add it 00244 { 00245 mStore.mUserStore.addUser( pUser, // user 00246 Data::Empty, // domain 00247 Data::Empty, // realm 00248 Data("admin"), // password 00249 Data::Empty, // name 00250 Data::Empty ); // email 00251 dbA1 = mStore.mUserStore.getUserAuthInfo( pUser, Data::Empty ); 00252 assert( !dbA1.empty() ); 00253 } 00254 #endif 00255 00256 if ( !dbA1.empty() ) 00257 { 00258 MD5Stream a1; 00259 a1 << pUser // username 00260 << Symbols::COLON 00261 << Data::Empty // realm 00262 << Symbols::COLON 00263 << pPassword; 00264 Data compA1 = a1.getHex(); 00265 00266 if ( dbA1 == compA1 ) 00267 { 00268 authenticatedUser = pUser; 00269 } 00270 else 00271 { 00272 InfoLog( << "user " << pUser << " failed to authenticate to web server" ); 00273 DebugLog( << " compA1="<<compA1<< " dbA1="<<dbA1 ); 00274 setPage( resip::Data::Empty, pageNumber,401 ); 00275 return; 00276 } 00277 } 00278 else //No A1, so we must assume this user does not exist. 00279 { 00280 setPage( "User does not exist.", pageNumber,401 ); 00281 return; 00282 } 00283 } 00284 00285 // parse any URI tags from form entry 00286 mRemoveSet.clear(); 00287 mHttpParams.clear(); 00288 00289 if (!pb.eof()) 00290 { 00291 pb.skipChar('?'); 00292 00293 while ( !pb.eof() ) 00294 { 00295 const char* anchor1 = pb.position(); 00296 pb.skipToChar('='); 00297 Data key; 00298 pb.data(key,anchor1); 00299 00300 const char* anchor2 = pb.skipChar('='); 00301 pb.skipToChar('&'); 00302 Data value; 00303 pb.data(value,anchor2); 00304 00305 if ( !pb.eof() ) 00306 { 00307 pb.skipChar('&'); 00308 } 00309 00310 if ( key.prefix("remove.") ) // special case of parameters to delete one or more records 00311 { 00312 Data tmp = key.substr(7); // the ID is everything after the dot 00313 if (!tmp.empty()) 00314 { 00315 DebugLog (<< " remove key=" << tmp.urlDecoded()); 00316 mRemoveSet.insert(RemoveKey(tmp.urlDecoded(),value.urlDecoded())); // add to the set of records to remove 00317 } 00318 } 00319 else if ( !key.empty() && !value.empty() ) // make sure both exist 00320 { 00321 DebugLog (<< " key=" << key << " value=" << value << " & unencoded form: " << value.urlDecoded() ); 00322 mHttpParams[key] = value.urlDecoded(); // add other parameters to the Map 00323 } 00324 } 00325 00326 } 00327 00328 DebugLog( << "building page for user=" << authenticatedUser ); 00329 00330 Data page; 00331 if ( authenticatedUser == Data("admin") ) 00332 { 00333 DataStream s(page); 00334 s << mPageOutlinePre; 00335 00336 // admin only pages 00337 if ( pageName == Data("user.html") ) {}; /* do nothing */ 00338 //if ( pageName == Data("input") ) ; /* do nothing */ 00339 if ( pageName == Data("domains.html") ) buildDomainsSubPage(s); 00340 if ( pageName == Data("acls.html") ) buildAclsSubPage(s); 00341 00342 if ( pageName == Data("addUser.html") ) buildAddUserSubPage(s); 00343 if ( pageName == Data("editUser.html") ) buildEditUserSubPage(s); 00344 if ( pageName == Data("showUsers.html") ) buildShowUsersSubPage(s); 00345 00346 if ( pageName == Data("addFilter.html") ) buildAddFilterSubPage(s); 00347 if ( pageName == Data("editFilter.html") ) buildEditFilterSubPage(s); 00348 if ( pageName == Data("showFilters.html") ) buildShowFiltersSubPage(s); 00349 00350 if ( pageName == Data("addRoute.html") ) buildAddRouteSubPage(s); 00351 if ( pageName == Data("editRoute.html") ) buildEditRouteSubPage(s); 00352 if ( pageName == Data("showRoutes.html") ) buildShowRoutesSubPage(s); 00353 00354 if ( pageName == Data("registrations.html")) buildRegistrationsSubPage(s); 00355 if ( pageName == Data("settings.html")) buildSettingsSubPage(s); 00356 00357 s << mPageOutlinePost; 00358 s.flush(); 00359 00360 if ( pageName == Data("userTest.html") ) page=buildUserPage(); 00361 } 00362 else if ( !authenticatedUser.empty() ) 00363 { 00364 // user only pages 00365 if ( pageName == Data("user.html") ) page=buildUserPage(); 00366 //if ( pageName == Data("input") ) page=buildUserPage(); 00367 } 00368 00369 assert( !authenticatedUser.empty() ); 00370 assert( !page.empty() ); 00371 00372 setPage( page, pageNumber,200 ); 00373 } 00374 00375 00376 void 00377 WebAdmin::buildDomainsSubPage(DataStream& s) 00378 { 00379 Data domainUri; 00380 int domainTlsPort; 00381 00382 if (!mRemoveSet.empty() && (mHttpParams["action"] == "Remove")) 00383 { 00384 int j = 0; 00385 for (set<RemoveKey>::iterator i = mRemoveSet.begin(); i != mRemoveSet.end(); ++i) 00386 { 00387 mStore.mConfigStore.eraseDomain(i->mKey1); 00388 ++j; 00389 } 00390 s << "<p><em>Removed:</em> " << j << " records</p>" << endl; 00391 } 00392 00393 Dictionary::iterator pos = mHttpParams.find("domainUri"); 00394 if (pos != mHttpParams.end() && (mHttpParams["action"] == "Add")) // found domainUri key 00395 { 00396 domainUri = pos->second; 00397 domainTlsPort = mHttpParams["domainTlsPort"].convertInt(); 00398 if(mStore.mConfigStore.addDomain(domainUri,domainTlsPort)) 00399 { 00400 s << "<p><em>Added</em> domain: " << domainUri << "</p>" << endl; 00401 } 00402 else 00403 { 00404 s << "<p><em>Error</em> adding domain: likely database error (check logs).</p>\n"; 00405 } 00406 } 00407 00408 s << 00409 " <h2>Domains</h2>" << endl << 00410 " <form id=\"domainForm\" method=\"get\" action=\"domains.html\" name=\"domainForm\">" << endl << 00411 " <table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 00412 " <tr>" << endl << 00413 " <td align=\"right\">New Domain:</td>" << endl << 00414 " <td><input type=\"text\" name=\"domainUri\" size=\"24\"/></td>" << endl << 00415 " <td><input type=\"text\" name=\"domainTlsPort\" size=\"4\"/></td>" << endl << 00416 " <td><input type=\"submit\" name=\"action\" value=\"Add\"/></td>" << endl << 00417 " </tr>" << endl << 00418 " </table>" << endl << 00419 " <div class=space>" << endl << 00420 " <br>" << endl << 00421 " </div>" << endl << 00422 " <table" REPRO_BORDERED_TABLE_PROPS ">" << endl << 00423 " <thead>" << endl << 00424 " <tr>" << endl << 00425 " <td>Domain</td>" << endl << 00426 " <td align=\"center\">TLS Port</td>" << endl << 00427 " <td><input type=\"submit\" name=\"action\" value=\"Remove\"/></td>" << endl << 00428 " </tr>" << endl << 00429 " </thead>" << endl << 00430 " <tbody>" << endl; 00431 00432 const ConfigStore::ConfigData& configs = mStore.mConfigStore.getConfigs(); 00433 for ( ConfigStore::ConfigData::const_iterator i = configs.begin(); 00434 i != configs.end(); i++ ) 00435 { 00436 s << 00437 " <tr>" << endl << 00438 " <td>" << i->second.mDomain << "</td>" << endl << 00439 " <td align=\"center\">" << i->second.mTlsPort << "</td>" << endl << 00440 " <td><input type=\"checkbox\" name=\"remove." << i->second.mDomain << "\"/></td>" << endl << 00441 " </tr>" << endl; 00442 } 00443 00444 s << 00445 " </tbody>" << endl << 00446 " </table>" << endl << 00447 " </form>" << endl << 00448 "<p><em>WARNING:</em> You must restart repro after adding domains.</p>" << endl; 00449 } 00450 00451 00452 void 00453 WebAdmin::buildAclsSubPage(DataStream& s) 00454 { 00455 if (!mRemoveSet.empty() && (mHttpParams["action"] == "Remove")) 00456 { 00457 int j = 0; 00458 for (set<RemoveKey>::iterator i = mRemoveSet.begin(); i != mRemoveSet.end(); ++i) 00459 { 00460 mStore.mAclStore.eraseAcl(i->mKey1); 00461 ++j; 00462 } 00463 s << "<p><em>Removed:</em> " << j << " records</p>" << endl; 00464 } 00465 00466 Dictionary::iterator pos = mHttpParams.find("aclUri"); 00467 if (pos != mHttpParams.end() && (mHttpParams["action"] == "Add")) // found 00468 { 00469 Data hostOrIp = mHttpParams["aclUri"]; 00470 int port = mHttpParams["aclPort"].convertInt(); 00471 TransportType transport = Tuple::toTransport(mHttpParams["aclTransport"]); 00472 00473 if (mStore.mAclStore.addAcl(hostOrIp, port, transport)) 00474 { 00475 s << "<p><em>Added</em> trusted access for: " << hostOrIp << "</p>\n"; 00476 } 00477 else 00478 { 00479 s << "<p>Error parsing: " << hostOrIp << "</p>\n"; 00480 } 00481 } 00482 00483 s << 00484 " <h2>ACLs</h2>" << endl << 00485 " <form id=\"aclsForm\" method=\"get\" action=\"acls.html\" name=\"aclsForm\">" << endl << 00486 " <div class=space>" << endl << 00487 " </div>" << endl << 00488 " <table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 00489 " <tr>" << endl << 00490 " <td align=\"right\">Host or IP:</td>" << endl << 00491 " <td><input type=\"text\" name=\"aclUri\" size=\"24\"/></td>" << endl << 00492 " <td><input type=\"text\" name=\"aclPort\" value=\"0\" size=\"5\"/></td>" << endl << 00493 " <td><select name=\"aclTransport\">" << endl << 00494 " <option selected=\"selected\">UDP</option>" << endl << 00495 " <option>TCP</option>" << endl << 00496 #ifdef USE_SSL 00497 " <option>TLS</option>" << endl << 00498 #endif 00499 #ifdef USE_DTLS 00500 " <option>DTLS</option>" << endl << 00501 #endif 00502 " </select></td>" << endl << 00503 " <td><input type=\"submit\" name=\"action\" value=\"Add\"/></td>" << endl << 00504 " </tr>" << endl << 00505 " </table>" << endl << 00506 " <br>" << endl << 00507 " <table" REPRO_BORDERED_TABLE_PROPS ">" << endl << 00508 " <thead>" << endl << 00509 " <tr>" << endl << 00510 " <td>Host Address or Peer Name</td>" << endl << 00511 " <td>Port</td>" << endl << 00512 " <td>Transport</td>" << endl << 00513 " <td><input type=\"submit\" name=\"action\" value=\"Remove\"/></td>" << endl << 00514 " </tr>" << endl << 00515 " </thead>" << endl << 00516 " <tbody>" << endl; 00517 00518 AclStore::Key key = mStore.mAclStore.getFirstTlsPeerNameKey(); 00519 while (key != Data::Empty) 00520 { 00521 s << 00522 " <tr>" << endl << 00523 " <td colspan=\"2\">" << mStore.mAclStore.getTlsPeerName(key) << "</td>" << endl << 00524 " <td>TLS auth</td>" << endl << 00525 " <td><input type=\"checkbox\" name=\"remove." << key << "\"/></td>" << endl << 00526 "</tr>" << endl; 00527 00528 key = mStore.mAclStore.getNextTlsPeerNameKey(key); 00529 } 00530 key = mStore.mAclStore.getFirstAddressKey(); 00531 while (key != Data::Empty) 00532 { 00533 s << 00534 " <tr>" << endl << 00535 " <td>" << mStore.mAclStore.getAddressTuple(key).presentationFormat() << "/" 00536 << mStore.mAclStore.getAddressMask(key) << "</td>" << endl << 00537 " <td>" << mStore.mAclStore.getAddressTuple(key).getPort() << "</td>" << endl << 00538 " <td>" << Tuple::toData(mStore.mAclStore.getAddressTuple(key).getType()) << "</td>" << endl << 00539 " <td><input type=\"checkbox\" name=\"remove." << key << "\"/></td>" << endl << 00540 " </tr>" << endl; 00541 key = mStore.mAclStore.getNextAddressKey(key); 00542 } 00543 00544 s << 00545 " </tbody>" << endl << 00546 " </table>" << endl << 00547 " </form>" << endl << 00548 00549 "<pre>" << endl << 00550 " Input can be in any of these formats" << endl << 00551 " localhost localhost (becomes 127.0.0.1/8, ::1/128 and fe80::1/64)" << endl << 00552 " bare hostname server1" << endl << 00553 " FQDN server1.example.com" << endl << 00554 " IPv4 address 192.168.1.100" << endl << 00555 " IPv4 + mask 192.168.1.0/24" << endl << 00556 " IPv6 address ::341:0:23:4bb:0011:2435:abcd" << endl << 00557 " IPv6 + mask ::341:0:23:4bb:0011:2435:abcd/80" << endl << 00558 " IPv6 reference [::341:0:23:4bb:0011:2435:abcd]" << endl << 00559 " IPv6 ref + mask [::341:0:23:4bb:0011:2435:abcd]/64" << endl << 00560 "</pre>" << endl << 00561 00562 "<p>Access lists are used as a whitelist to allow " << endl << 00563 "gateways and other trusted nodes to skip authentication.</p>" << endl << 00564 "<p>Note: If hostnames or FQDN's are used then a TLS transport type is" << endl << 00565 "assumed. All other transport types must specify ACLs by address.</p>" << endl; 00566 } 00567 00568 00569 void 00570 WebAdmin::buildAddUserSubPage( DataStream& s) 00571 { 00572 Dictionary::iterator pos; 00573 Data user; 00574 00575 pos = mHttpParams.find("user"); 00576 if (pos != mHttpParams.end()) // found user key 00577 { 00578 user = pos->second; 00579 Data domain = mHttpParams["domain"]; 00580 00581 // pos = mHttpParams.find("realm"); 00582 // if (pos == mHttpParams.end()) 00583 // { 00584 // realm = mHttpParams["domain"]; 00585 // } 00586 00587 if(mStore.mUserStore.addUser(user,domain,domain,mHttpParams["password"],true,mHttpParams["name"],mHttpParams["email"])) 00588 { 00589 s << "<p><em>Added:</em> " << user << "@" << domain << "</p>\n"; 00590 } 00591 else 00592 { 00593 s << "<p><em>Error</em> adding user: likely database error (check logs).</p>\n"; 00594 } 00595 } 00596 00597 s << 00598 "<h2>Add User</h2>" << endl << 00599 "<form id=\"addUserForm\" action=\"addUser.html\" method=\"get\" name=\"addUserForm\" enctype=\"application/x-www-form-urlencoded\">" << endl << 00600 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 00601 "<tr>" << endl << 00602 " <td align=\"right\" valign=\"middle\">User Name:</td>" << endl << 00603 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"user\" size=\"40\"/></td>" << endl << 00604 "</tr>" << endl << 00605 00606 //"<tr>" << endl << 00607 //"<td align=\"right\" valign=\"middle\" >Realm:</td>" << endl << 00608 //"<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"realm\" size=\"40\"/></td>" << endl << 00609 //"</tr>" << endl << 00610 00611 "<tr>" << endl << 00612 " <td align=\"right\" valign=\"middle\" >Domain:</td>" << endl << 00613 " <td align=\"left\" valign=\"middle\"><select name=\"domain\">" << endl 00614 ; 00615 00616 // for each domain, add an option in the pulldown 00617 const ConfigStore::ConfigData& list = mStore.mConfigStore.getConfigs(); 00618 for ( ConfigStore::ConfigData::const_iterator i = list.begin(); 00619 i != list.end(); i++ ) 00620 { 00621 s << " <option"; 00622 00623 // if i->Domain is the default domain 00624 // { 00625 // s << " selected=\"true\""; 00626 // } 00627 00628 s << ">" << i->second.mDomain << "</option>" << endl; 00629 } 00630 00631 s << 00632 "</select></td></tr>" << endl << 00633 "<tr>" << endl << 00634 " <td align=\"right\" valign=\"middle\" >Password:</td>" << endl << 00635 " <td align=\"left\" valign=\"middle\"><input type=\"password\" name=\"password\" size=\"40\"/></td>" << endl << 00636 "</tr>" << endl << 00637 00638 "<tr>" << endl << 00639 " <td align=\"right\" valign=\"middle\" >Full Name:</td>" << endl << 00640 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"name\" size=\"40\"/></td>" << endl << 00641 "</tr>" << endl << 00642 00643 "<tr>" << endl << 00644 " <td align=\"right\" valign=\"middle\" >Email:</td>" << endl << 00645 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"email\" size=\"40\"/></td>" << endl << 00646 "</tr>" << endl << 00647 00648 "<tr>" << endl << 00649 " <td colspan=\"2\" align=\"right\" valign=\"middle\">" << endl << 00650 " <input type=\"reset\" value=\"Cancel\"/>" << endl << 00651 " <input type=\"submit\" name=\"submit\" value=\"Add\"/>" << endl << 00652 " </td>" << endl << 00653 "</tr>" << endl << 00654 00655 "</table>" << endl << 00656 "</form>" << endl 00657 ; 00658 } 00659 00660 00661 void 00662 WebAdmin::buildEditUserSubPage( DataStream& s) 00663 { 00664 Dictionary::iterator pos; 00665 pos = mHttpParams.find("key"); 00666 if (pos != mHttpParams.end()) 00667 { 00668 Data key = pos->second; 00669 AbstractDb::UserRecord rec = mStore.mUserStore.getUserInfo(key); 00670 // !rwm! TODO check to see if we actually found a record corresponding to the key. how do we do that? 00671 00672 s << "<h2>Edit User</h2>" << endl << 00673 "<p>Editing Record with key: " << key << "</p>" << endl << 00674 "<p>Note: If the username is not modified and you leave the password field empty the users current password will not be reset.</p>" << endl; 00675 00676 s << 00677 "<form id=\"editUserForm\" action=\"showUsers.html\" method=\"get\" name=\"editUserForm\" enctype=\"application/x-www-form-urlencoded\">" << endl << 00678 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 00679 "<input type=\"hidden\" name=\"key\" value=\"" << key << "\"/>" << endl << 00680 "<tr>" << endl << 00681 " <td align=\"right\" valign=\"middle\">User Name:</td>" << endl << 00682 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"user\" value=\"" << rec.user << "\" size=\"40\"/></td>" << endl << 00683 "</tr>" << endl << 00684 00685 //"<tr>" << endl << 00686 //"<td align=\"right\" valign=\"middle\" >Realm:</td>" << endl << 00687 //"<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"realm\" size=\"40\"/></td>" << endl << 00688 //"</tr>" << endl << 00689 00690 "<tr>" << endl << 00691 " <td align=\"right\" valign=\"middle\" >Domain:</td>" << endl << 00692 " <td align=\"left\" valign=\"middle\"><select name=\"domain\">" << endl 00693 ; 00694 00695 // for each domain, add an option in the pulldown 00696 const ConfigStore::ConfigData& list = mStore.mConfigStore.getConfigs(); 00697 for ( ConfigStore::ConfigData::const_iterator i = list.begin(); 00698 i != list.end(); i++ ) 00699 { 00700 s << " <option"; 00701 00702 if ( i->second.mDomain == rec.domain) 00703 { 00704 s << " selected=\"true\""; 00705 } 00706 00707 s << ">" << i->second.mDomain << "</option>" << endl; 00708 } 00709 00710 s << 00711 "</select></td></tr>" << endl << 00712 "<tr>" << endl << 00713 " <td align=\"right\" valign=\"middle\" >Password:</td>" << endl << 00714 " <td align=\"left\" valign=\"middle\"><input type=\"password\" name=\"password\" size=\"40\"/></td>" << endl << 00715 "</tr>" << endl << 00716 // Note that the UserStore only stores a passwordHash, so we will collect a password. If one is provided in the 00717 // edit page, we will use it to generate a new passwordHash, otherwise we will leave the hash alone. 00718 00719 "<tr>" << endl << 00720 " <td align=\"right\" valign=\"middle\" >Full Name:</td>" << endl << 00721 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"name\" value=\"" << rec.name << 00722 "\" size=\"40\"/></td>" << endl << 00723 "</tr>" << endl << 00724 00725 "<tr>" << endl << 00726 " <td align=\"right\" valign=\"middle\" >Email:</td>" << endl << 00727 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"email\" value=\"" << rec.email << 00728 "\" size=\"40\"/></td>" << endl << 00729 "</tr>" << endl << 00730 00731 "<tr>" << endl << 00732 " <td colspan=\"2\" align=\"right\" valign=\"middle\">" << endl << 00733 " <input type=\"submit\" name=\"submit\" value=\"Update\"/>" << endl << 00734 " </td>" << endl << 00735 "</tr>" << endl << 00736 00737 "</table>" << endl << 00738 "</form>" << endl 00739 ; 00740 } 00741 else 00742 { 00743 // go back to show users page 00744 } 00745 } 00746 00747 00748 void 00749 WebAdmin::buildShowUsersSubPage(DataStream& s) 00750 { 00751 Dictionary::iterator pos; 00752 Data key; 00753 AbstractDb::UserRecord rec; 00754 00755 if (!mRemoveSet.empty()) 00756 { 00757 int j = 0; 00758 for (set<RemoveKey>::iterator i = mRemoveSet.begin(); i != mRemoveSet.end(); ++i) 00759 { 00760 mStore.mUserStore.eraseUser(i->mKey1); 00761 ++j; 00762 } 00763 s << "<p><em>Removed:</em> " << j << " records</p>" << endl; 00764 } 00765 00766 pos = mHttpParams.find("key"); 00767 if (pos != mHttpParams.end()) // check if the user parameter exists, if so, use as a key to update the record 00768 { 00769 key = pos->second; 00770 rec = mStore.mUserStore.getUserInfo(key); 00771 // check to see if we actually found a record corresponding to the key 00772 if (!rec.user.empty()) 00773 { 00774 Data user = mHttpParams["user"]; 00775 Data domain = mHttpParams["domain"]; 00776 Data realm = mHttpParams["domain"]; // eventually sort out realms 00777 Data password = mHttpParams["password"]; 00778 Data name = mHttpParams["name"]; 00779 Data email = mHttpParams["email"]; 00780 bool applyA1HashToPassword = true; 00781 00782 // if no password was specified, then leave current password untouched 00783 if(password == "" && user == rec.user && realm == rec.realm) 00784 { 00785 password = rec.passwordHash; 00786 applyA1HashToPassword = false; 00787 } 00788 // write out the updated record to the database now 00789 if(mStore.mUserStore.updateUser(key, user, domain, realm, password, applyA1HashToPassword, name, email)) 00790 { 00791 s << "<p><em>Updated:</em> " << key << "</p>" << endl; 00792 } 00793 else 00794 { 00795 s << "<p><em>Error</em> updating user: likely database error (check logs).</p>\n"; 00796 } 00797 } 00798 } 00799 00800 00801 s << 00802 "<h2>Users</h2>" << endl << 00803 "<form id=\"showUsers\" method=\"get\" action=\"showUsers.html\" name=\"showUsers\" enctype=\"application/x-www-form-urlencoded\">" << endl << 00804 "<table" REPRO_BORDERED_TABLE_PROPS ">" << endl << 00805 "<tr>" << endl << 00806 " <td>User@Domain</td>" << endl << 00807 // " <td>Realm</td>" << endl << 00808 " <td>Name</td>" << endl << 00809 " <td>Email</td>" << endl << 00810 " <td><input type=\"submit\" value=\"Remove\"/></td>" << endl << 00811 "</tr>" << endl; 00812 00813 s << endl; 00814 00815 int count =0; 00816 00817 key = mStore.mUserStore.getFirstKey(); 00818 while ( !key.empty() ) 00819 { 00820 rec = mStore.mUserStore.getUserInfo(key); 00821 00822 if ((rec.domain == Data::Empty) && (rec.user == "admin")) 00823 { 00824 key = mStore.mUserStore.getNextKey(); 00825 continue; // skip the row for the admin web user 00826 } 00827 00828 s << "<tr>" << endl 00829 << " <td><a href=\"editUser.html?key="; 00830 key.urlEncode(s); 00831 s << "\">" << rec.user << "@" << rec.domain << "</a></td>" << endl 00832 << " <td>" << rec.name << "</td>" << endl 00833 << " <td>" << rec.email << "</td>" << endl 00834 << " <td><input type=\"checkbox\" name=\"remove." << key << "\"/></td>" << endl 00835 << "</tr>" << endl; 00836 00837 key = mStore.mUserStore.getNextKey(); 00838 00839 // make a limit to how many users are displayed 00840 if ( ++count > 1000 ) 00841 { 00842 break; 00843 } 00844 } 00845 00846 if ( !key.empty() ) 00847 { 00848 s << "<tr><td>Only first 1000 users were displayed<td></tr>" << endl; 00849 } 00850 00851 s << 00852 "</table>" << endl << 00853 "</form>" << endl; 00854 } 00855 00856 void 00857 WebAdmin::buildAddFilterSubPage(DataStream& s) 00858 { 00859 Dictionary::iterator pos; 00860 00861 pos = mHttpParams.find("cond1header"); 00862 if (pos != mHttpParams.end()) 00863 { 00864 Data action = mHttpParams["action"]; 00865 Data actionData = mHttpParams["actiondata"]; 00866 00867 if (action != "Accept" && actionData.empty()) 00868 { 00869 s << "<p><em>Error</em> adding request filter. You must provide appropriate Action Data for non-Accept action.</p>\n"; 00870 } 00871 else 00872 { 00873 short actionShort = 0; // 0 - Accept, 1 - Reject, 2 - SQL Query 00874 if(action == "Reject") actionShort = 1; 00875 else if(action == "SQL Query") actionShort = 2; 00876 00877 if(mStore.mFilterStore.addFilter(mHttpParams["cond1header"], 00878 mHttpParams["cond1regex"], 00879 mHttpParams["cond2header"], 00880 mHttpParams["cond2regex"], 00881 mHttpParams["method"], 00882 mHttpParams["event"], 00883 actionShort, 00884 actionData, 00885 mHttpParams["order"].convertInt())) 00886 { 00887 s << "<p><em>Added</em> request filter: " << mHttpParams["cond1header"] << "=" << mHttpParams["cond1regex"] << ", " 00888 << mHttpParams["cond2header"] << "=" << mHttpParams["cond2regex"] << "</p>\n"; 00889 } 00890 else 00891 { 00892 s << "<p><em>Error</em> adding request filter, likely duplicate found.</p>\n"; 00893 } 00894 } 00895 } 00896 00897 s << 00898 "<h2>Add Request Filter</h2>" << endl << 00899 "<form id=\"addFilterForm\" method=\"get\" action=\"addFilter.html\" name=\"addFilterForm\">" << endl << 00900 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 00901 00902 "<tr>" << endl << 00903 " <td align=\"right\" valign=\"middle\">Condition1 Header:</td>" << endl << 00904 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond1header\" size=\"40\" value=\"From\"/></td>" << endl << 00905 "</tr>" << endl << 00906 00907 "<tr>" << endl << 00908 " <td align=\"right\" valign=\"middle\">Condition1 Regex:</td>" << endl << 00909 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond1regex\" size=\"40\"/></td>" << endl << 00910 "</tr>" << endl << 00911 00912 "<tr>" << endl << 00913 " <td align=\"right\" valign=\"middle\">Condition2 Header:</td>" << endl << 00914 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond2header\" size=\"40\" value=\"To\"/></td>" << endl << 00915 "</tr>" << endl << 00916 00917 "<tr>" << endl << 00918 " <td align=\"right\" valign=\"middle\">Condition2 Regex:</td>" << endl << 00919 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond2regex\" size=\"40\"/></td>" << endl << 00920 "</tr>" << endl << 00921 00922 "<tr>" << endl << 00923 " <td align=\"right\" valign=\"middle\">Method:</td>" << endl << 00924 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"method\" size=\"40\"/></td>" << endl << 00925 "</tr>" << endl << 00926 00927 "<tr>" << endl << 00928 " <td align=\"right\" valign=\"middle\">Event:</td>" << endl << 00929 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"event\" size=\"40\"/></td>" << endl << 00930 "</tr>" << endl << 00931 00932 "<tr>" << endl << 00933 " <td align=\"right\" valign=\"middle\">Action:</td>" << endl << 00934 " <td align=\"left\" valign=\"middle\">" << endl << 00935 " <select name=\"action\">" << endl << 00936 " <option>Reject</option>" << endl << 00937 " <option>Accept</option>" << endl << 00938 #ifdef USE_MYSQL 00939 " <option>SQL Query</option>" << endl << 00940 #endif 00941 " </select>" << endl << 00942 " </td>" << endl << 00943 "</tr>" << endl << 00944 00945 "<tr>" << endl << 00946 " <td align=\"right\" valign=\"middle\">Action Data:</td>" << endl << 00947 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"actiondata\" size=\"40\" value=\"403, Request Blocked\"/></td>" << endl << 00948 "</tr>" << endl << 00949 00950 "<tr>" << endl << 00951 " <td align=\"right\" valign=\"middle\">Order:</td>" << endl << 00952 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"order\" size=\"4\" value=\"0\"/></td>" << endl << 00953 "</tr>" << endl << 00954 00955 "<tr>" << endl << 00956 " <td colspan=\"2\" align=\"right\" valign=\"middle\">" << endl << 00957 " <input type=\"reset\" value=\"Cancel\"/>" << endl << 00958 " <input type=\"submit\" name=\"filterAdd\" value=\"Add\"/>" << endl << 00959 " </td>" << endl << 00960 "</tr>" << endl << 00961 00962 "</table>" << endl << 00963 "</form>" << endl << 00964 00965 "<pre>" << endl << 00966 "If Action is Accept, then Action Data is ignored." << endl << 00967 "If Action is Reject, then Action Data should be set to: SIPRejectionCode[, SIPReason]" << endl << 00968 #ifdef USE_MYSQL 00969 "If Action is SQL Query, then Action Data should be set to the SQL Query to execute." << endl << 00970 "Replacement strings from the Regex's above can be used in the query, and the query" << endl << 00971 "must return a string that is formated similar to Action Data when the action is" << endl << 00972 "Reject. Alternatively it can return a string with status code of 0 to accept the" << endl << 00973 "request." << endl << 00974 #endif 00975 "</pre>" << endl; 00976 } 00977 00978 00979 void 00980 WebAdmin::buildEditFilterSubPage(DataStream& s) 00981 { 00982 Dictionary::iterator pos; 00983 pos = mHttpParams.find("key"); 00984 if (pos != mHttpParams.end()) 00985 { 00986 Data key = pos->second; 00987 00988 // !rwm! TODO check to see if we actually found a record corresponding to the key. how do we do that? 00989 DebugLog( << "Creating page to edit filter " << key ); 00990 00991 AbstractDb::FilterRecord rec = mStore.mFilterStore.getFilterRecord(key); 00992 00993 s <<"<h2>Edit Request Filter</h2>" << endl << 00994 "<p>Editing Record with conditions: " << rec.mCondition1Header << "=" << rec.mCondition1Regex << ", " 00995 << rec.mCondition2Header << "=" << rec.mCondition2Regex << "</p>" << endl; 00996 00997 s << 00998 "<form id=\"editFilterForm\" method=\"get\" action=\"showFilters.html\" name=\"editFilterForm\">" << endl << 00999 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 01000 "<input type=\"hidden\" name=\"key\" value=\"" << key << "\"/>" << endl << 01001 "<tr>" << endl << 01002 01003 "<tr>" << endl << 01004 " <td align=\"right\" valign=\"middle\">Condition1 Header:</td>" << endl << 01005 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond1header\" size=\"40\" value=\"" << rec.mCondition1Header.xmlCharDataEncode() << "\"/></td>" << endl << 01006 "</tr>" << endl << 01007 01008 "<tr>" << endl << 01009 " <td align=\"right\" valign=\"middle\">Condition1 Regex:</td>" << endl << 01010 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond1regex\" size=\"40\" value=\"" << rec.mCondition1Regex.xmlCharDataEncode() << "\"/></td>" << endl << 01011 "</tr>" << endl << 01012 01013 "<tr>" << endl << 01014 " <td align=\"right\" valign=\"middle\">Condition2 Header:</td>" << endl << 01015 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond2header\" size=\"40\" value=\"" << rec.mCondition2Header.xmlCharDataEncode() << "\"/></td>" << endl << 01016 "</tr>" << endl << 01017 01018 "<tr>" << endl << 01019 " <td align=\"right\" valign=\"middle\">Condition2 Regex:</td>" << endl << 01020 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"cond2regex\" size=\"40\" value=\"" << rec.mCondition2Regex.xmlCharDataEncode() << "\"/></td>" << endl << 01021 "</tr>" << endl << 01022 01023 "<tr>" << endl << 01024 " <td align=\"right\" valign=\"middle\">Method:</td>" << endl << 01025 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"method\" size=\"40\" value=\"" << rec.mMethod << "\"/></td>" << endl << 01026 "</tr>" << endl << 01027 01028 "<tr>" << endl << 01029 " <td align=\"right\" valign=\"middle\">Event:</td>" << endl << 01030 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"event\" size=\"40\" value=\"" << rec.mEvent << "\"/></td>" << endl << 01031 "</tr>" << endl << 01032 01033 "<tr>" << endl << 01034 " <td align=\"right\" valign=\"middle\">Action:</td>" << endl << 01035 " <td align=\"left\" valign=\"middle\">" << endl << 01036 " <select name=\"action\">" << endl << 01037 " <option" << (rec.mAction == FilterStore::Reject ? " selected=\"selected\"" : "") << ">Reject</option>" << endl << 01038 " <option" << (rec.mAction == FilterStore::Accept ? " selected=\"selected\"" : "") << ">Accept</option>" << endl << 01039 #ifdef USE_MYSQL 01040 " <option" << (rec.mAction == FilterStore::SQLQuery ? " selected=\"selected\"" : "") << ">SQL Query</option>" << endl << 01041 #endif 01042 " </select>" << endl << 01043 " </td>" << endl << 01044 "</tr>" << endl << 01045 01046 "<tr>" << endl << 01047 " <td align=\"right\" valign=\"middle\">Action Data:</td>" << endl << 01048 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"actiondata\" size=\"40\" value=\"" << rec.mActionData.xmlCharDataEncode() << "\"/></td>" << endl << 01049 "</tr>" << endl << 01050 01051 "<tr>" << endl << 01052 " <td align=\"right\" valign=\"middle\">Order:</td>" << endl << 01053 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"order\" size=\"4\" value=\"" << rec.mOrder << "\"/></td>" << endl << 01054 "</tr>" << endl << 01055 01056 "<tr>" << endl << 01057 " <td colspan=\"2\" align=\"right\" valign=\"middle\">" << endl << 01058 " <input type=\"submit\" name=\"routeEdit\" value=\"Update\"/>" << endl << 01059 " </td>" << endl << 01060 "</tr>" << endl << 01061 01062 "</table>" << endl << 01063 "</form>" << endl; 01064 } 01065 else 01066 { 01067 // go back to show filter page 01068 } 01069 } 01070 01071 01072 void 01073 WebAdmin::buildShowFiltersSubPage(DataStream& s) 01074 { 01075 Dictionary::iterator pos; 01076 Data key; 01077 AbstractDb::RouteRecord rec; 01078 01079 if (!mRemoveSet.empty()) 01080 { 01081 int j = 0; 01082 for (set<RemoveKey>::iterator i = mRemoveSet.begin(); i != mRemoveSet.end(); ++i) 01083 { 01084 mStore.mFilterStore.eraseFilter(i->mKey1); 01085 ++j; 01086 } 01087 s << "<p><em>Removed:</em> " << j << " records</p>" << endl; 01088 } 01089 01090 pos = mHttpParams.find("key"); 01091 if (pos != mHttpParams.end()) // if a key parameter exists, use the key to update the record 01092 { 01093 key = pos->second; 01094 01095 // !rwm! TODO check to see if we actually found a record corresponding to the key. how do we do that? 01096 if (1) 01097 { 01098 Data action = mHttpParams["action"]; 01099 Data actionData = mHttpParams["actiondata"]; 01100 01101 if (action != "Accept" && actionData.empty()) 01102 { 01103 s << "<p><em>Error</em> updating request filter. You must provide appropriate Action Data for non-Accept action.</p>\n"; 01104 } 01105 else 01106 { 01107 short actionShort = 0; // 0 - Accept, 1 - Reject, 2 - SQL Query 01108 if(action == "Reject") actionShort = 1; 01109 else if(action == "SQL Query") actionShort = 2; 01110 01111 if(mStore.mFilterStore.updateFilter(key, 01112 mHttpParams["cond1header"], 01113 mHttpParams["cond1regex"], 01114 mHttpParams["cond2header"], 01115 mHttpParams["cond2regex"], 01116 mHttpParams["method"], 01117 mHttpParams["event"], 01118 actionShort, 01119 actionData, 01120 mHttpParams["order"].convertInt())) 01121 { 01122 s << "<p><em>Updated</em> request filter: " << mHttpParams["cond1header"] << "=" << mHttpParams["cond1regex"] << ", " 01123 << mHttpParams["cond2header"] << "=" << mHttpParams["cond2regex"] << "</p>\n"; 01124 } 01125 else 01126 { 01127 s << "<p><em>Error</em> updating request filter: likely database error (check logs).</p>\n"; 01128 } 01129 } 01130 } 01131 } 01132 01133 s << 01134 "<h2>Request Filters</h2>" << endl << 01135 "<form id=\"showFilters\" action=\"showFilters.html\" method=\"get\" name=\"showFilters\" enctype=\"application/x-www-form-urlencoded\">" << endl << 01136 // " <button name=\"removeAllRoute\" value=\"\" type=\"submit\">Remove All</button>" << endl << 01137 "<table" REPRO_BORDERED_TABLE_PROPS ">" << endl << 01138 "<thead><tr>" << endl << 01139 " <td>Condition 1</td>" << endl << 01140 " <td>Condition 2</td>" << endl << 01141 " <td>Method</td>" << endl << 01142 " <td>Event</td>" << endl << 01143 " <td>Action</td>" << endl << 01144 " <td>Action Data</td>" << endl << 01145 " <td>Order</td>" << endl << 01146 " <td><input type=\"submit\" value=\"Remove\"/></td>" << endl << 01147 "</tr></thead>" << endl << 01148 "<tbody>" << endl; 01149 01150 for(FilterStore::Key key = mStore.mFilterStore.getFirstKey(); 01151 !key.empty(); 01152 key = mStore.mFilterStore.getNextKey(key)) 01153 { 01154 AbstractDb::FilterRecord rec = mStore.mFilterStore.getFilterRecord(key); 01155 Data action("Accept"); 01156 if(rec.mAction == FilterStore::Reject) 01157 { 01158 action = "Reject"; 01159 } 01160 else if(rec.mAction == FilterStore::SQLQuery) 01161 { 01162 action = "SQL Query"; 01163 } 01164 s << "<tr>" << endl << 01165 "<td><a href=\"editFilter.html?key="; 01166 key.urlEncode(s); 01167 s << 01168 "\">" << rec.mCondition1Header << "=" << rec.mCondition1Regex << "</a></td>" << endl << 01169 "<td>" << rec.mCondition2Header << "=" << rec.mCondition2Regex << "</td>" << endl << 01170 "<td>" << rec.mMethod << "</td>" << endl << 01171 "<td>" << rec.mEvent << "</td>" << endl << 01172 "<td>" << action << "</td>" << endl << 01173 "<td>" << rec.mActionData << "</td>" << endl << 01174 "<td>" << rec.mOrder << "</td>" << endl << 01175 "<td><input type=\"checkbox\" name=\"remove." << key << "\"/></td>" << endl << 01176 "</tr>" << endl; 01177 } 01178 01179 s << 01180 "</tbody>" << endl << 01181 "</table>" << endl << 01182 "</form>" << endl; 01183 01184 Data cond1TestHeader; 01185 pos = mHttpParams.find("cond1TestHeader"); 01186 if (pos != mHttpParams.end()) // found it 01187 { 01188 cond1TestHeader = pos->second; 01189 } 01190 Data cond2TestHeader; 01191 pos = mHttpParams.find("cond2TestHeader"); 01192 if (pos != mHttpParams.end()) // found it 01193 { 01194 cond2TestHeader = pos->second; 01195 } 01196 01197 s << 01198 "<br><form id=\"testFilter\" action=\"showFilters.html\" method=\"get\" name=\"testFilter\" enctype=\"application/x-www-form-urlencoded\">" << endl << 01199 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 01200 "<tr>" << endl << 01201 " <td align=\"right\">Condition 1 Header:</td>" << endl << 01202 " <td><input type=\"text\" name=\"cond1TestHeader\" value=\"" << cond1TestHeader.xmlCharDataEncode() << "\" size=\"40\"/></td>" << endl << 01203 "</tr>" << endl << 01204 "<tr>" << endl << 01205 " <td align=\"right\">Condition 2 Header:</td>" << endl << 01206 " <td><input type=\"text\" name=\"cond2TestHeader\" value=\"" << cond2TestHeader.xmlCharDataEncode() << "\" size=\"40\"/></td>" << endl << 01207 " <td><input type=\"submit\" name=\"testFilter\" value=\"Test Filters\"/></td>" << endl << 01208 "</tr>" << endl << 01209 "</table>" << endl << 01210 "</form>" << endl << 01211 "<br>" << endl; 01212 01213 if(!cond1TestHeader.empty()) 01214 { 01215 s << "<em>Test Result: </em>"; 01216 short action; 01217 Data actionData; 01218 if(mStore.mFilterStore.test(cond1TestHeader, cond2TestHeader, action, actionData)) 01219 { 01220 switch(action) 01221 { 01222 case FilterStore::Reject: 01223 s << "Match found, action=Reject " << actionData << endl; 01224 break; 01225 case FilterStore::SQLQuery: 01226 s << "Match found, action=SQL Query '" << actionData << "'" << endl; 01227 break; 01228 case FilterStore::Accept: 01229 default: 01230 s << "Match found, action=Accept" << endl; 01231 break; 01232 } 01233 } 01234 else 01235 { 01236 s << "No Match"; 01237 } 01238 } 01239 } 01240 01241 01242 void 01243 WebAdmin::buildAddRouteSubPage(DataStream& s) 01244 { 01245 Dictionary::iterator pos; 01246 01247 pos = mHttpParams.find("routeUri"); 01248 if (pos != mHttpParams.end()) 01249 { 01250 Data routeUri = mHttpParams["routeUri"]; 01251 Data routeDestination = mHttpParams["routeDestination"]; 01252 01253 if (!routeUri.empty() && !routeDestination.empty()) 01254 { 01255 if(mStore.mRouteStore.addRoute(mHttpParams["routeMethod"], 01256 mHttpParams["routeEvent"], 01257 routeUri, 01258 routeDestination, 01259 mHttpParams["routeOrder"].convertInt())) 01260 { 01261 s << "<p><em>Added</em> route for: " << routeUri << "</p>\n"; 01262 } 01263 else 01264 { 01265 s << "<p><em>Error</em> adding route, likely duplicate found.</p>\n"; 01266 } 01267 } 01268 else 01269 { 01270 s << "<p><em>Error</em> adding route. You must provide a URI and a route destination.</p>\n"; 01271 } 01272 } 01273 01274 s << 01275 "<h2>Add Route</h2>" << endl << 01276 "<form id=\"addRouteForm\" method=\"get\" action=\"addRoute.html\" name=\"addRouteForm\">" << endl << 01277 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 01278 01279 "<tr>" << endl << 01280 " <td align=\"right\" valign=\"middle\">URI:</td>" << endl << 01281 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeUri\" size=\"40\"/></td>" << endl << 01282 "</tr>" << endl << 01283 01284 "<tr>" << endl << 01285 " <td align=\"right\" valign=\"middle\">Method:</td>" << endl << 01286 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeMethod\" size=\"40\"/></td>" << endl << 01287 "</tr>" << endl << 01288 01289 "<tr>" << endl << 01290 " <td align=\"right\" valign=\"middle\">Event:</td>" << endl << 01291 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeEvent\" size=\"40\"/></td>" << endl << 01292 "</tr>" << endl << 01293 01294 "<tr>" << endl << 01295 " <td align=\"right\" valign=\"middle\">Destination:</td>" << endl << 01296 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeDestination\" size=\"40\"/></td>" << endl << 01297 "</tr>" << endl << 01298 01299 "<tr>" << endl << 01300 " <td align=\"right\" valign=\"middle\">Order:</td>" << endl << 01301 " <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeOrder\" size=\"4\"/></td>" << endl << 01302 "</tr>" << endl << 01303 01304 "<tr>" << endl << 01305 " <td colspan=\"2\" align=\"right\" valign=\"middle\">" << endl << 01306 " <input type=\"reset\" value=\"Cancel\"/>" << endl << 01307 " <input type=\"submit\" name=\"routeAdd\" value=\"Add\"/>" << endl << 01308 " </td>" << endl << 01309 "</tr>" << endl << 01310 01311 "</table>" << endl << 01312 "</form>" << endl << 01313 01314 "<pre>" << endl << 01315 "Static routes use (POSIX-standard) regular expression to match" << endl << 01316 "and rewrite SIP URIs. The following is an example of sending" << endl << 01317 "all requests that consist of only digits in the userpart of the" << endl << 01318 "SIP URI to a gateway:" << endl << endl << 01319 " URI: ^sip:([0-9]+)@example\\.com" << endl << 01320 " Destination: sip:$1@gateway.example.com" << endl << 01321 "</pre>" << endl; 01322 } 01323 01324 01325 void 01326 WebAdmin::buildEditRouteSubPage(DataStream& s) 01327 { 01328 Dictionary::iterator pos; 01329 pos = mHttpParams.find("key"); 01330 if (pos != mHttpParams.end()) 01331 { 01332 Data key = pos->second; 01333 01334 // !rwm! TODO check to see if we actually found a record corresponding to the key. how do we do that? 01335 DebugLog( << "Creating page to edit route " << key ); 01336 01337 AbstractDb::RouteRecord rec = mStore.mRouteStore.getRouteRecord(key); 01338 01339 s <<"<h2>Edit Route</h2>" << endl << 01340 "<p>Editing Record with matching pattern: " << rec.mMatchingPattern << "</p>" << endl; 01341 01342 s << 01343 "<form id=\"editRouteForm\" method=\"get\" action=\"showRoutes.html\" name=\"editRouteForm\">" << endl << 01344 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 01345 "<input type=\"hidden\" name=\"key\" value=\"" << key << "\"/>" << endl << 01346 "<tr>" << endl << 01347 "<td align=\"right\" valign=\"middle\">URI:</td>" << endl << 01348 "<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeUri\" value=\"" << rec.mMatchingPattern << "\" size=\"40\"/></td>" << endl << 01349 "</tr>" << endl << 01350 01351 "<tr>" << endl << 01352 "<td align=\"right\" valign=\"middle\">Method:</td>" << endl << 01353 "<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeMethod\" value=\"" << rec.mMethod << "\" size=\"40\"/></td>" << endl << 01354 "</tr>" << endl << 01355 01356 "<tr>" << endl << 01357 "<td align=\"right\" valign=\"middle\">Event:</td>" << endl << 01358 "<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeEvent\" value=\"" << rec.mEvent << "\" size=\"40\"/></td>" << endl << 01359 "</tr>" << endl << 01360 01361 "<tr>" << endl << 01362 "<td align=\"right\" valign=\"middle\">Destination:</td>" << endl << 01363 "<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeDestination\" value=\"" << rec.mRewriteExpression << 01364 "\" size=\"40\"/></td>" << endl << 01365 "</tr>" << endl << 01366 01367 "<tr>" << endl << 01368 "<td align=\"right\" valign=\"middle\">Order:</td>" << endl << 01369 "<td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"routeOrder\" value=\"" << rec.mOrder << 01370 "\" size=\"4\"/></td>" << endl << 01371 "</tr>" << endl << 01372 01373 "<tr>" << endl << 01374 " <td colspan=\"2\" align=\"right\" valign=\"middle\">" << endl << 01375 " <input type=\"submit\" name=\"routeEdit\" value=\"Update\"/>" << endl << 01376 " </td>" << endl << 01377 "</tr>" << endl << 01378 01379 "</table>" << endl << 01380 "</form>" << endl; 01381 } 01382 else 01383 { 01384 // go back to show route page 01385 } 01386 } 01387 01388 01389 void 01390 WebAdmin::buildShowRoutesSubPage(DataStream& s) 01391 { 01392 Dictionary::iterator pos; 01393 Data key; 01394 AbstractDb::RouteRecord rec; 01395 01396 if (!mRemoveSet.empty()) 01397 { 01398 int j = 0; 01399 for (set<RemoveKey>::iterator i = mRemoveSet.begin(); i != mRemoveSet.end(); ++i) 01400 { 01401 mStore.mRouteStore.eraseRoute(i->mKey1); 01402 ++j; 01403 } 01404 s << "<p><em>Removed:</em> " << j << " records</p>" << endl; 01405 } 01406 01407 pos = mHttpParams.find("key"); 01408 if (pos != mHttpParams.end()) // if a key parameter exists, use the key to update the record 01409 { 01410 key = pos->second; 01411 01412 // !rwm! TODO check to see if we actually found a record corresponding to the key. how do we do that? 01413 if (1) 01414 { 01415 Data method = mHttpParams["routeMethod"]; 01416 Data event = mHttpParams["routeEvent"]; 01417 Data matchingPattern = mHttpParams["routeUri"]; 01418 Data rewriteExpression = mHttpParams["routeDestination"]; 01419 int order = mHttpParams["routeOrder"].convertInt(); 01420 01421 if (!matchingPattern.empty() && !rewriteExpression.empty()) 01422 { 01423 // write out the updated record to the database now 01424 if(mStore.mRouteStore.updateRoute(key, method, event, matchingPattern, rewriteExpression, order)) 01425 { 01426 s << "<p><em>Updated:</em> " << rec.mMatchingPattern << "</p>" << endl; 01427 } 01428 else 01429 { 01430 s << "<p><em>Error</em> updating route: likely database error (check logs).</p>\n"; 01431 } 01432 } 01433 else 01434 { 01435 s << "<p><em>Error</em> updating route. You must provide a URI and a route destination.</p>\n"; 01436 } 01437 } 01438 } 01439 01440 s << 01441 "<h2>Routes</h2>" << endl << 01442 "<form id=\"showRoutes\" action=\"showRoutes.html\" method=\"get\" name=\"showRoutes\" enctype=\"application/x-www-form-urlencoded\">" << endl << 01443 // " <button name=\"removeAllRoute\" value=\"\" type=\"submit\">Remove All</button>" << endl << 01444 "<table" REPRO_BORDERED_TABLE_PROPS ">" << endl << 01445 "<thead><tr>" << endl << 01446 " <td>URI</td>" << endl << 01447 " <td>Method</td>" << endl << 01448 " <td>Event</td>" << endl << 01449 " <td>Destination</td>" << endl << 01450 " <td>Order</td>" << endl << 01451 " <td><input type=\"submit\" value=\"Remove\"/></td>" << endl << 01452 "</tr></thead>" << endl << 01453 "<tbody>" << endl; 01454 01455 for ( RouteStore::Key key = mStore.mRouteStore.getFirstKey(); 01456 !key.empty(); 01457 key = mStore.mRouteStore.getNextKey(key) ) 01458 { 01459 AbstractDb::RouteRecord rec = mStore.mRouteStore.getRouteRecord(key); 01460 01461 s << "<tr>" << endl << 01462 "<td><a href=\"editRoute.html?key="; 01463 key.urlEncode(s); 01464 s << 01465 "\">" << rec.mMatchingPattern << "</a></td>" << endl << 01466 "<td>" << rec.mMethod << "</td>" << endl << 01467 "<td>" << rec.mEvent << "</td>" << endl << 01468 "<td>" << rec.mRewriteExpression << "</td>" << endl << 01469 "<td>" << rec.mOrder << "</td>" << endl << 01470 "<td><input type=\"checkbox\" name=\"remove." << key << "\"/></td>" << endl << 01471 "</tr>" << endl; 01472 } 01473 01474 s << 01475 "</tbody>" << endl << 01476 "</table>" << endl << 01477 "</form>" << endl; 01478 01479 int badUri = true; 01480 Uri uri; 01481 Data routeTestUri; 01482 01483 pos = mHttpParams.find("routeTestUri"); 01484 if (pos != mHttpParams.end()) // found it 01485 { 01486 routeTestUri = pos->second; 01487 if ( routeTestUri != "sip:" ) 01488 { 01489 try 01490 { 01491 uri = Uri(routeTestUri); 01492 badUri=false; 01493 } 01494 catch( BaseException& ) 01495 { 01496 try 01497 { 01498 uri = Uri( Data("sip:")+routeTestUri ); 01499 badUri=false; 01500 } 01501 catch( BaseException& ) 01502 { 01503 } 01504 } 01505 } 01506 } 01507 01508 // !cj! - TODO - should input method and event type to test 01509 RouteStore::UriList routeList; 01510 if (!badUri) 01511 { 01512 routeList = mStore.mRouteStore.process(uri, Data("INVITE"), Data::Empty); 01513 } 01514 01515 s << 01516 "<br><form id=\"testRoute\" action=\"showRoutes.html\" method=\"get\" name=\"testRoute\" enctype=\"application/x-www-form-urlencoded\">" << endl << 01517 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 01518 "<tr>" << endl << 01519 " <td align=\"right\">Input:</td>" << endl << 01520 " <td><input type=\"text\" name=\"routeTestUri\" value=\"" << uri << "\" size=\"40\"/></td>" << endl << 01521 " <td><input type=\"submit\" name=\"testRoute\" value=\"Test Routes\"/></td>" << endl << 01522 "</tr>" << endl; 01523 01524 bool first=true; 01525 for ( RouteStore::UriList::const_iterator i=routeList.begin(); 01526 i != routeList.end(); i++) 01527 { 01528 s<<" <tr>" << endl; 01529 if (first) 01530 { 01531 first=false; 01532 s<<" <td align=\"right\">Targets:</td>" << endl; 01533 } 01534 else 01535 { 01536 s<<" <td align=\"right\"></td>" << endl; 01537 } 01538 s<<" <td><label>" << *i << "</label></td>" << endl; 01539 s<<" <td></td>" << endl; 01540 s<<" </tr>" << endl; 01541 } 01542 01543 s<< 01544 "</table>" << endl << 01545 "</form>" << endl; 01546 } 01547 01548 01549 void 01550 WebAdmin::buildRegistrationsSubPage(DataStream& s) 01551 { 01552 if (!mRemoveSet.empty()) 01553 { 01554 int j = 0; 01555 for (set<RemoveKey>::iterator i = mRemoveSet.begin(); i != mRemoveSet.end(); ++i) 01556 { 01557 Uri aor(i->mKey1); 01558 ContactInstanceRecord rec; 01559 size_t bar1 = i->mKey2.find("|"); 01560 size_t bar2 = i->mKey2.find("|",bar1+1); 01561 size_t bar3 = i->mKey2.find("|",bar2+1); 01562 01563 if(bar1==Data::npos || bar2 == Data::npos || bar3==Data::npos) 01564 { 01565 InfoLog(<< "Registration removal key was malformed: " << i->mKey2); 01566 continue; 01567 } 01568 01569 bool staticRegContact=false; 01570 try 01571 { 01572 resip::Data rawNameAddr = i->mKey2.substr(0,bar1).urlDecoded(); 01573 rec.mContact = NameAddr(rawNameAddr); 01574 rec.mInstance = i->mKey2.substr(bar1+1,bar2-bar1-1).urlDecoded(); 01575 rec.mRegId = i->mKey2.substr(bar2+1,Data::npos).convertInt(); 01576 staticRegContact = i->mKey2.substr(bar3+1,Data::npos).convertInt() == 1; 01577 01578 // Remove from RegistrationPersistanceManager 01579 mRegDb.removeContact(aor, rec); 01580 01581 if(staticRegContact) 01582 { 01583 // Remove from StateRegStore 01584 mStore.mStaticRegStore.eraseStaticReg(aor, rec.mContact); 01585 } 01586 01587 ++j; 01588 } 01589 catch(resip::ParseBuffer::Exception& e) 01590 { 01591 InfoLog(<< "Registration removal key was malformed: " << e << 01592 " Key was: " << i->mKey2); 01593 } 01594 } 01595 s << "<p><em>Removed:</em> " << j << " records</p>" << endl; 01596 } 01597 01598 Dictionary::iterator pos = mHttpParams.find("regAor"); 01599 if (pos != mHttpParams.end() && (mHttpParams["action"] == "Add")) // found 01600 { 01601 Data regAor = mHttpParams["regAor"]; 01602 Data regContact = mHttpParams["regContact"]; 01603 Data regPath = mHttpParams["regPath"]; 01604 01605 ContactInstanceRecord rec; 01606 try 01607 { 01608 rec.mContact = NameAddr(regContact); 01609 try 01610 { 01611 ParseBuffer pb(regPath); 01612 Data path; 01613 const char* anchor = pb.position(); 01614 while(!pb.eof()) 01615 { 01616 pb.skipToChar(Symbols::COMMA[0]); 01617 pb.data(path, anchor); 01618 rec.mSipPath.push_back(NameAddr(path)); 01619 if(!pb.eof()) pb.skipChar(); // skip over comma 01620 anchor = pb.position(); 01621 } 01622 try 01623 { 01624 rec.mRegExpires = NeverExpire; 01625 rec.mSyncContact = true; // Tag this permanent contact as being a syncronized contact so that it will 01626 // be syncronized to a paired server (this is actually configuration information) 01627 01628 // Add to DB Store 01629 Uri aor(regAor); 01630 if(mStore.mStaticRegStore.addStaticReg(aor, rec.mContact, rec.mSipPath)) 01631 { 01632 // Add to RegistrationPersistanceManager 01633 mRegDb.updateContact(aor, rec); 01634 01635 s << "<p><em>Added</em> permanent registered contact for: " << regAor << "</p>\n"; 01636 } 01637 else 01638 { 01639 s << "<p><em>Error</em> adding static registration: likely database error (check logs).</p>\n"; 01640 } 01641 } 01642 catch(resip::ParseBuffer::Exception& e) 01643 { 01644 InfoLog(<< "Registration add: aor " << regAor << " was malformed: " << e); 01645 s << "<p>Error parsing: AOR=" << regAor << "</p>\n"; 01646 } 01647 } 01648 catch(resip::ParseBuffer::Exception& e) 01649 { 01650 InfoLog(<< "Registration add: path " << regPath << " was malformed: " << e); 01651 s << "<p>Error parsing: Path=" << regPath << "</p>\n"; 01652 } 01653 } 01654 catch(resip::ParseBuffer::Exception& e) 01655 { 01656 InfoLog(<< "Registration add: contact " << regContact << " was malformed: " << e); 01657 s << "<p>Error parsing: Contact=" << regContact << "</p>\n"; 01658 } 01659 } 01660 01661 s << 01662 "<h2>Registrations</h2>" << endl << 01663 "<form id=\"showReg\" method=\"get\" action=\"registrations.html\" name=\"showReg\" enctype=\"application/x-www-form-urlencoded\">" << endl << 01664 //"<button name=\"removeAllReg\" value=\"\" type=\"button\">Remove All</button>" << endl << 01665 //"<hr/>" << endl << 01666 01667 "<div class=space>" << endl << 01668 "</div>" << endl << 01669 "<table" REPRO_BORDERLESS_TABLE_PROPS ">" << endl << 01670 " <tr>" << endl << 01671 " <td align=\"right\">AOR:</td>" << endl << 01672 " <td><input type=\"text\" name=\"regAor\" size=\"40\"/></td>" << endl << 01673 " <td align=\"right\">Contact:</td>" << endl << 01674 " <td><input type=\"text\" name=\"regContact\" size=\"40\"/></td>" << endl << 01675 " </tr>" << endl << 01676 " <tr>" << endl << 01677 " <td align=\"right\">Path:</td>" << endl << 01678 " <td><input type=\"text\" name=\"regPath\" size=\"40\"/></td>" << endl << 01679 " <td></td>" << endl << 01680 " <td align=\"right\"><input type=\"submit\" name=\"action\" value=\"Add\"/></td>" << endl << 01681 " </tr>" << endl << 01682 " </tr>" << endl << 01683 "</table>" << endl << 01684 "<br>" << endl << 01685 01686 "<table" REPRO_BORDERED_TABLE_PROPS ">" << endl << 01687 01688 "<tr>" << endl << 01689 " <td>AOR</td>" << endl << 01690 " <td>Contact</td>" << endl << 01691 " <td>Instance ID</td>" << endl << 01692 " <td>Reg ID</td>" << endl << 01693 " <td>QValue</td>" << endl << 01694 " <td>Path</td>" << endl << 01695 " <td>Expires In</td>" << endl << 01696 " <td><input type=\"submit\" value=\"Remove\"/></td>" << endl << 01697 "</tr>" << endl; 01698 01699 RegistrationPersistenceManager::UriList aors; 01700 mRegDb.getAors(aors); 01701 for ( RegistrationPersistenceManager::UriList::const_iterator 01702 aor = aors.begin(); aor != aors.end(); ++aor ) 01703 { 01704 Uri uri = *aor; 01705 ContactList contacts; 01706 mRegDb.getContacts(uri, contacts); 01707 01708 bool first = true; 01709 UInt64 now = Timer::getTimeSecs(); 01710 for (ContactList::iterator i = contacts.begin(); 01711 i != contacts.end(); ++i ) 01712 { 01713 if(i->mRegExpires > now) 01714 { 01715 UInt64 secondsRemaining = i->mRegExpires - now; 01716 01717 s << "<tr>" << endl 01718 << " <td>" ; 01719 if (first) 01720 { 01721 s << uri; 01722 first = false; 01723 } 01724 s << "</td>" << endl 01725 << " <td>"; 01726 01727 const ContactInstanceRecord& r = *i; 01728 const NameAddr& contact = r.mContact; 01729 const Data& instanceId = r.mInstance; 01730 int regId = r.mRegId; 01731 01732 s << contact.uri(); 01733 s <<"</td>" << endl 01734 << "<td>" << instanceId.xmlCharDataEncode() 01735 << "</td><td>" << regId 01736 << "</td><td>"; 01737 #ifdef RESIP_FIXED_POINT 01738 // If RESIP_FIXED_POINT is enabled then q-value is shown as an integer in the range of 0..1000 where 1000 = qvalue of 1.0 01739 s << (contact.exists(p_q) ? contact.param(p_q) : 1000) << "</td><td>"; 01740 #else 01741 s << (contact.exists(p_q) ? contact.param(p_q).floatVal() : 1.0f) << "</td><td>"; 01742 #endif 01743 NameAddrs::const_iterator naIt = r.mSipPath.begin(); 01744 for(;naIt != r.mSipPath.end(); naIt++) 01745 { 01746 s << naIt->uri() << "<br>" << endl; 01747 } 01748 bool staticRegContact = r.mRegExpires == NeverExpire; 01749 if(!staticRegContact) 01750 { 01751 s <<"</td><td>" << secondsRemaining << "s</td>" << endl; 01752 } 01753 else 01754 { 01755 s <<"</td><td>Never</td>" << endl; 01756 } 01757 s << " <td>" 01758 << "<input type=\"checkbox\" name=\"remove." << uri << "\" value=\"" << Data::from(contact.uri()).urlEncoded() 01759 << "|" << instanceId.urlEncoded() 01760 << "|" << regId 01761 << "|" << (staticRegContact ? "1" : "0") 01762 << "\"/></td>" << endl 01763 << "</tr>" << endl; 01764 } 01765 else 01766 { 01767 // remove expired contact 01768 mRegDb.removeContact(uri, *i); 01769 } 01770 } 01771 } 01772 01773 s << "</table>" << endl << 01774 "</form>" << endl; 01775 } 01776 01777 01778 void 01779 WebAdmin::buildSettingsSubPage(DataStream& s) 01780 { 01781 s << "<h2>Settings</h2>" << endl << 01782 "<pre>" << mProxy.getConfig() << "</pre>"; 01783 01784 { 01785 Data buffer; 01786 DataStream strm(buffer); 01787 mProxy.getStack().dump(strm); 01788 strm.flush(); 01789 s << "<br>Stack Info<br>" 01790 << "<pre>" << buffer << "</pre>" 01791 << endl; 01792 } 01793 01794 if(mProxy.getStack().getCongestionManager()) 01795 { 01796 Data buffer; 01797 DataStream strm(buffer); 01798 mProxy.getStack().getCongestionManager()->encodeCurrentState(strm); 01799 s << "<br>Congestion Manager Statistics<br>" 01800 << "<pre>" << buffer << "</pre>" 01801 << endl; 01802 } 01803 } 01804 01805 01806 Data 01807 WebAdmin::buildUserPage() 01808 { 01809 Data ret; 01810 { 01811 DataStream s(ret); 01812 01813 s << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl 01814 << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl 01815 << "" << endl 01816 << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl 01817 << "" << endl 01818 << "<head>" << endl 01819 << "<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />" << endl 01820 << "<title>Repro Proxy</title>" << endl 01821 << "</head>" << endl 01822 << "" << endl 01823 << "<body bgcolor=\"#ffffff\">" << endl; 01824 01825 //buildAddUserSubPage(s); // !cj! TODO - should do beter page here 01826 01827 s << "</body>" << endl 01828 << "" << endl 01829 << "</html>" << endl; 01830 01831 s.flush(); 01832 } 01833 return ret; 01834 } 01835 01836 01837 Data 01838 WebAdmin::buildCertPage(const Data& domain) 01839 { 01840 assert(!domain.empty()); 01841 #ifdef USE_SSL 01842 assert( mProxy.getStack().getSecurity() ); 01843 return mProxy.getStack().getSecurity()->getDomainCertDER(domain); 01844 #else 01845 ErrLog( << "Proxy not build with support for certificates" ); 01846 return Data::Empty; 01847 #endif 01848 } 01849 01850 01851 Data 01852 WebAdmin::buildDefaultPage() 01853 { 01854 Data ret; 01855 { 01856 DataStream s(ret); 01857 01858 s << 01859 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << 01860 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl << 01861 "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl << 01862 "<head>" << endl << 01863 "<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />" << endl << 01864 "<title>Repro Proxy Login</title>" << endl << 01865 "</head>" << endl << 01866 01867 "<body bgcolor=\"#ffffff\">" << endl << 01868 " <h1><a href=\"user.html\">Login</a></h1>" << endl << 01869 " <p>The default account is 'admin' with password 'admin', but if you're wise, you've already changed that using the command line</p>" << endl << 01870 "</body>" << endl << 01871 "</html>" << endl; 01872 01873 s.flush(); 01874 } 01875 return ret; 01876 } 01877 01878 01879 /* ==================================================================== 01880 * The Vovida Software License, Version 1.0 01881 * 01882 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 01883 * 01884 * Redistribution and use in source and binary forms, with or without 01885 * modification, are permitted provided that the following conditions 01886 * are met: 01887 * 01888 * 1. Redistributions of source code must retain the above copyright 01889 * notice, this list of conditions and the following disclaimer. 01890 * 01891 * 2. Redistributions in binary form must reproduce the above copyright 01892 * notice, this list of conditions and the following disclaimer in 01893 * the documentation and/or other materials provided with the 01894 * distribution. 01895 * 01896 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 01897 * and "Vovida Open Communication Application Library (VOCAL)" must 01898 * not be used to endorse or promote products derived from this 01899 * software without prior written permission. For written 01900 * permission, please contact vocal@vovida.org. 01901 * 01902 * 4. Products derived from this software may not be called "VOCAL", nor 01903 * may "VOCAL" appear in their name, without prior written 01904 * permission of Vovida Networks, Inc. 01905 * 01906 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 01907 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 01908 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 01909 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 01910 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 01911 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 01912 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 01913 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 01914 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 01915 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01916 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 01917 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 01918 * DAMAGE. 01919 * 01920 * ==================================================================== 01921 */
1.7.5.1