reSIProcate/repro  9694
WebAdmin.cxx
Go to the documentation of this file.
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  */