// a class to maintain the PICS data. It reads and write it to the metabase and // reads the file and all that. It also serves as a wrapper for the PICS parsing // objects that have already been written elsewhere // Created 4/18/97 by BoydM #include "stdafx.h" #include #include "cnfgprts.h" #include "parserat.h" #include "RatData.h" #include #include #include "metatool.h" #include #include "mdobjs.h" #include // Here is the plan. First, we scan the local directory - looking for all // the .rat files, load them and parse them //---------------------------------------------------------------- CRatingsData::CRatingsData(IMSAdminBase* pMB): iRat(0), m_fEnabled( FALSE ), m_start_minute(0), m_start_hour(0), m_start_day(0), m_start_month(0), m_start_year(0), m_expire_minute(0), m_expire_hour(0), m_expire_day(0), m_expire_month(0), m_expire_year(0), m_pMB( pMB ) { } //---------------------------------------------------------------- CRatingsData::~CRatingsData() { // delete the rating systems DWORD nRats = (DWORD)rgbRats.GetSize(); for ( DWORD iRat = 0; iRat < nRats; iRat++ ) delete rgbRats[iRat]; } //---------------------------------------------------------------- BOOL CRatingsData::FCreateURL( CString &sz ) { CHAR nameBuf[MAX_PATH+1]; // start it off with the mandatory http header sz.LoadString( IDS_HTTP_HEADER ); // get the host name of the machine if ( gethostname( nameBuf, sizeof(nameBuf)) ) return FALSE; sz += nameBuf; // next, we need to add on the virtual path supplied by the metabase location // but that means starting by finding the root portion of the string CString szVir = m_szMeta; CString szRoot = _T("/Root"); szVir = szVir.Right( szVir.GetLength() - szVir.Find(szRoot) ); szVir = szVir.Right( szVir.GetLength() - szRoot.GetLength() ); // concatenate and done sz += szVir; return TRUE; } //---------------------------------------------------------------- // generate the label and save it into the metabase void CRatingsData::SaveTheLable() { BOOL fBuiltLabel = FALSE; BOOL f; // prepare the metabase wrapper CWrapMetaBase mbWrap; f = mbWrap.FInit(m_pMB); if ( !f ) return; // if the rating is NOT enabled, delete any existing label and return if ( !m_fEnabled ) { // attempt to open the object we want to store into if ( mbWrap.Open( m_szMeta, METADATA_PERMISSION_WRITE ) ) { // delete any existing PICS metaobject // f = mbWrap.DeleteData( _T(""), MD_HTTP_PICS, IIS_MD_UT_FILE, MULTISZ_METADATA ); f = mbWrap.DeleteData( _T(""), MD_HTTP_PICS, MULTISZ_METADATA ); // close the metabase mbWrap.Close(); } //leave return; } else { CString szLabel; // first, we add the actual HTTP header to the header // szLabel = _T("Protocol: {PICS-1.0 {headers PICS-Label}}\nPICS-Label: "); szLabel = _T("PICS-Label: "); // create the URL string for this label CString szURL; FCreateURL( szURL ); // create the modified string for this label CString szMod; CreateDateSz( szMod, m_start_day, m_start_month, m_start_year, m_start_hour, m_start_minute ); // create the exipres string for this label CString szExpire; CreateDateSz( szExpire, m_expire_day, m_expire_month, m_expire_year, m_expire_hour, m_expire_minute ); // tell each ratings system object to add its label to the string DWORD nRatingSystems = (DWORD)rgbRats.GetSize(); for ( DWORD iRat = 0; iRat < nRatingSystems; iRat++ ) { // build the label string rgbRats[iRat]->OutputLabels( szLabel, szURL, m_szEmail, szMod, szExpire ); } // the data gets saved as a multisz, so prep it up PTCHAR psz = szLabel.GetBuffer( szLabel.GetLength()+4 ); DWORD dw = szLabel.GetLength(); // add the second null psz[dw + 1] = 0; psz[dw + 2] = 0; // save the data // save the PICS header string // f = SetMetaData(&mbWrap, szPartial, MD_HTTP_PICS, IIS_MD_UT_FILE, // psz, szLabel.GetLength()+2 ); // f = SetMetaMultiSz( &mbWrap, m_szMeta, MD_HTTP_PICS, IIS_MD_UT_FILE, // psz, dw+2 ); f = SetMetaMultiSz(m_pMB, m_szServer, m_szMeta, _T(""), MD_HTTP_PICS, IIS_MD_UT_FILE, psz, dw+2, TRUE ); // release the buffer szLabel.ReleaseBuffer(); // these changes are permanent - so write them out if ( f ) mbWrap.Save(); } } //---------------------------------------------------------------- BOOL CRatingsData::FInit( CString szServer, CString szMeta ) { CWinApp* pApp = AfxGetApp(); CString sz; BOOL fGotSomething = FALSE; BOOL fFoundAFile = FALSE; // store the target metabase location m_szServer = szServer; m_szMeta = szMeta; // build the search string CString szSearch; // the ratings files are in the system32 directory. First, get that // directory from the system. The first call is to get the size of the buffer. // add one for the terminating NULL DWORD cchSysDir = GetSystemDirectory( NULL, 0 ) + 1; // if we didn't get one - fail if ( cchSysDir == 1 ) return FALSE; // Now get it for real cchSysDir = GetSystemDirectory( szSearch.GetBuffer(cchSysDir), cchSysDir ); szSearch.ReleaseBuffer(); // if we didn't get one - fail if ( !cchSysDir ) return FALSE; // finish making it a proper search string // // RONALDM -- add .rat to only find rat files. // szSearch += _T("\\*.rat"); // scan the local files looking for rat files. For each we find, load // them into the list of rat files BOOL fKeepGoing = TRUE; CFileFind finder; fFoundAFile = finder.FindFile( szSearch ); while ( fFoundAFile ) { // get rid of the directories right away if ( finder.MatchesMask( FILE_ATTRIBUTE_DIRECTORY ) ) { // get the next file fFoundAFile = finder.FindNextFile(); continue; } // get and normalize the path sz = finder.GetFilePath(); sz.MakeLower(); // if it is a rat file, go for it // // RONALDM -- changed the mask so that this is all that's necc. // //if ( sz.Find(_T(".rat")) > 0 ) { // set the found flag based on if we can load it fGotSomething |= FLoadRatingsFile( sz ); } // get the next file if ( !fKeepGoing ) { fFoundAFile = FALSE; } else { fKeepGoing = finder.FindNextFile(); } } // if we loaded a file, check what is in the metabase and load the values if ( fGotSomething ) { LoadMetabaseValues(); } else { // if we didn't find any rat files, tell the user and return AfxMessageBox( IDS_RAT_FINDFILE_ERROR ); } // return the answer return fGotSomething; } //---------------------------------------------------------------- // load a ratings file BOOL CRatingsData::FLoadRatingsFile( CString szFilePath ) { HANDLE hFile; HANDLE hFileMapping; VOID * pMem; BOOL fParsed = FALSE; hFile = CreateFile( szFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { return FALSE; } hFileMapping = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); if ( hFileMapping == NULL ) { CloseHandle( hFile ); return FALSE; } pMem = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 ); if ( pMem == NULL ) { CloseHandle( hFileMapping ); CloseHandle( hFile ); return FALSE; } // parse this and load it in and all that stuff fParsed = FParseRatingsFile( (LPSTR) pMem, szFilePath ); UnmapViewOfFile( pMem ); CloseHandle( hFileMapping ); CloseHandle( hFile ); // return the answer return fParsed; } //---------------------------------------------------------------- BOOL CRatingsData::FParseRatingsFile( LPSTR pData, CString szPath ) { HRESULT hres; BOOL fSuccess = FALSE; // first, try and parse the data PicsRatingSystem* pRating = new PicsRatingSystem(); // parse the data hres = pRating->Parse( pData ); fSuccess = (hres == 0); // if it didn't parse, leave now if ( !fSuccess ) { delete pRating; return FALSE; } // add the rat to the list of parsed rats rgbRats.Add( pRating ); return fSuccess; } //---------------------------------------------------------------- // create a date string void CRatingsData::CreateDateSz( CString &sz, WORD day, WORD month, WORD year, WORD hour, WORD minute ) { // get the local time zone TIME_ZONE_INFORMATION tZone; INT hrZone, mnZone; DWORD dwDaylight = GetTimeZoneInformation( &tZone ); // Fix for 339525: Boyd, this could be negative and must be signed type! LONG tBias; // First, calculate the correct bias - depending whether or not // we are in daylight savings time. if ( dwDaylight == TIME_ZONE_ID_DAYLIGHT ) { tBias = tZone.Bias + tZone.DaylightBias; } else { tBias = tZone.Bias + tZone.StandardBias; } // calculate the hours and minutes offset for the time-zone hrZone = tBias / 60; mnZone = tBias % 60; // need to handle time zones east of GMT if ( hrZone < 0 ) { hrZone *= (-1); mnZone *= (-1); // make the string sz.Format( _T("%04d.%02d.%02dT%02d:%02d+%02d%02d"), year, month, day, hour, minute, hrZone, mnZone ); } else { // make the string sz.Format( _T("%04d.%02d.%02dT%02d:%02d-%02d%02d"), year, month, day, hour, minute, hrZone, mnZone ); } } //---------------------------------------------------------------- // read a date string void CRatingsData::ReadDateSz( CString sz, WORD* pDay, WORD* pMonth, WORD* pYear, WORD* pHour, WORD* pMinute ) { CString szNum; WORD i; DWORD dw; // year szNum = sz.Left( sz.Find(_T('.')) ); i = (WORD)swscanf( szNum, _T("%d"), &dw ); *pYear = (WORD)dw; sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 ); // month szNum = sz.Left( sz.Find(_T('.')) ); i = (WORD)swscanf( szNum, _T("%d"), &dw ); *pMonth = (WORD)dw; sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 ); // day szNum = sz.Left( sz.Find(_T('T')) ); i = (WORD)swscanf( szNum, _T("%d"), &dw ); *pDay = (WORD)dw; sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 ); // hour szNum = sz.Left( sz.Find(_T(':')) ); i = (WORD)swscanf( szNum, _T("%d"), &dw ); *pHour = (WORD)dw; sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 ); // minute szNum = sz.Left( 2 ); i = (WORD)swscanf( szNum, _T("%d"), &dw ); *pMinute = (WORD)dw; } //---------------------------------------------------------------- // for simplicity's sake (and for the sake of gettings done) only check the // metabase values against the first loaded ratings system. Everything I've // been hearing is that there will be only one. void CRatingsData::LoadMetabaseValues() { CString szRating; BOOL f; // prepare the metabase wrapper CWrapMetaBase mbWrap; f = mbWrap.FInit(m_pMB); if ( !f ) return; // if we succeded in building the lables, save it in the metabase // attempt to open the object we want to store into CString szMeta; // arg arg arg. For things like directories, the metapath may not exist // seperate the partial path from the base - the root is always SZ_ROOT szMeta = SZ_W3_ROOT; m_szMetaPartial = m_szMeta.Right(m_szMeta.GetLength() - szMeta.GetLength() ); // save the data if ( mbWrap.Open( szMeta, METADATA_PERMISSION_READ ) ) { DWORD cbData; // attempt to read the data from the metabase WCHAR* pData= (WCHAR*)mbWrap.GetData( m_szMetaPartial, MD_HTTP_PICS, IIS_MD_UT_FILE, MULTISZ_METADATA, &cbData, METADATA_INHERIT | METADATA_PARTIAL_PATH ); // copy the string into place if ( pData ) szRating = pData; // free the buffer mbWrap.FreeWrapData( pData ); // close the metabase mbWrap.Close(); // if we got the string, parse it and all that jazz if ( !szRating.IsEmpty() ) ParseMetaRating( szRating ); } } //---------------------------------------------------------------- // NOTE: this is a pretty fragile reading of the PICS file. If things are // not in the order that this file would write them back out in, it will fail. // however, This will work on PICS ratings that this module has written out, // which should pretty much be all of them // it also assumes that one-letter abbreviations are used just about everywhere #define RAT_PERSON_DETECTOR _T("by \"") #define RAT_LABEL_DETECTOR _T("l ") #define RAT_ON_DETECTOR _T("on \"") #define RAT_EXPIRE_DETECTOR _T("exp \"") #define RAT_RAT_DETECTOR _T("r (") void CRatingsData::ParseMetaRating( CString szRating ) { CString szScratch; // if we got here, then we know that the rating system is enabled m_fEnabled = TRUE; // operate on a copy of the data CString szRat; // skip past the http headerpart szRat = szRating.Right( szRating.GetLength() - szRating.Find(_T("\"http://")) - 1 ); szRat = szRat.Right( szRat.GetLength() - szRat.Find(_T('\"')) - 1 ); szRat.TrimLeft(); // the next bit should be the label indicator. Skip over it if ( szRat.Left(wcslen(RAT_LABEL_DETECTOR)) == RAT_LABEL_DETECTOR ) szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_LABEL_DETECTOR) ); // we should now be at the author part. If it is there, load it in if ( szRat.Left(wcslen(RAT_PERSON_DETECTOR)) == RAT_PERSON_DETECTOR ) { szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_PERSON_DETECTOR) ); m_szEmail = szRat.Left( szRat.Find(_T('\"')) ); szRat = szRat.Right( szRat.GetLength() - m_szEmail.GetLength() - 1 ); szRat.TrimLeft(); } // next should be the modification date // we should now be at the author part. If we are, load it in if ( szRat.Left(wcslen(RAT_ON_DETECTOR)) == RAT_ON_DETECTOR ) { szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_ON_DETECTOR) ); szScratch = szRat.Left( szRat.Find(_T('\"')) ); szRat = szRat.Right( szRat.GetLength() - szScratch.GetLength() - 1 ); szRat.TrimLeft(); ReadDateSz( szScratch, &m_start_day, &m_start_month, &m_start_year, &m_start_hour, &m_start_minute ); } // next should be the expiration date // we should now be at the author part. If we are, load it in if ( szRat.Left(wcslen(RAT_EXPIRE_DETECTOR)) == RAT_EXPIRE_DETECTOR ) { szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_EXPIRE_DETECTOR) ); szScratch = szRat.Left( szRat.Find(_T('\"')) ); szRat = szRat.Right( szRat.GetLength() - szScratch.GetLength() - 1 ); szRat.TrimLeft(); ReadDateSz( szScratch, &m_expire_day, &m_expire_month, &m_expire_year, &m_expire_hour, &m_expire_minute ); } // we should now be at the actual ratings part. If we are, load it in as one string first if ( szRat.Left(wcslen(RAT_RAT_DETECTOR)) == RAT_RAT_DETECTOR ) { szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_RAT_DETECTOR) ); szScratch = szRat.Left( szRat.Find(_T(')')) ); szRat = szRat.Right( szRat.GetLength() - szScratch.GetLength() - 1 ); szRat.TrimLeft(); // loop through all the value pairs in the ratings string while ( szScratch.GetLength() ) { // this part goes sp so that we know we can use chars 0 and 2 ParseMetaPair( szScratch[0], szScratch[2] ); // cut down the string szScratch = szScratch.Right( szScratch.GetLength() - 3 ); szScratch.TrimLeft(); } } } //---------------------------------------------------------------- void CRatingsData::ParseMetaPair( TCHAR chCat, TCHAR chVal ) { // check validity of the value character if ( (chVal < _T('0')) || (chVal > _T('9')) ) return; // convert the value into a number - the quick way WORD value = chVal - _T('0'); // try all the categories DWORD nCat = rgbRats[0]->arrpPC.Length(); for ( DWORD iCat = 0; iCat < nCat; iCat++ ) { // stop at the first successful setting if ( rgbRats[0]->arrpPC[iCat]->FSetValuePair((CHAR)chCat, (CHAR)value) ) break; } }