/*++ Microsoft Windows Copyright (C) Microsoft Corporation, 1981 - 2000 Module Name: path.cxx Abstract: Implementation of the methods in the CRedirPath class. This class parses a path and breaks it up into different components and categorizes it into one of the well known paths: (a) a path in the local user profile location (b) a path in the user's home directory (c) a specific user specified path (d) a per-user path in a user specified location Author: Rahul Thombre (RahulTh) 3/3/2000 Revision History: 3/3/2000 RahulTh Created this module. --*/ #include "precomp.hxx" CRedirPath::CRedirPath(UINT cookie) : _bDataValid (FALSE), _cookie(cookie) { _szPrefix.Empty(); _szSuffix.Empty(); } //+-------------------------------------------------------------------------- // // Member: CRedirPath::GeneratePath // // Synopsis: Generate the full path from the components // // Arguments: [out] szPath : the generated path // [in, optional] szUser : sample username // // Returns: TRUE : if the generated path is valid. // FALSE: if there is no valid path stored in this object. In // this case szPath is set to an empty string. // // History: 3/3/2000 RahulTh created // // Notes: For per user paths, this function uses a sample username // if supplied, otherwise, it uses the username variable // string %username% // //--------------------------------------------------------------------------- BOOL CRedirPath::GeneratePath (OUT CString & szPath, OPTIONAL IN const CString & szUser //= USERNAME_STR ) const { BOOL bStatus; if (! _bDataValid) return FALSE; szPath = L""; bStatus = TRUE; switch (_type) { case IDS_SPECIFIC_PATH: szPath = _szPrefix; if (! IsValidPrefix (_type, (LPCTSTR) _szPrefix)) bStatus = FALSE; break; case IDS_HOMEDIR_PATH: szPath = HOMEDIR_STR; if (!_szSuffix.IsEmpty()) szPath += _szSuffix; bStatus = TRUE; break; case IDS_PERUSER_PATH: if (_szPrefix.IsEmpty() || ! IsValidPrefix (_type, (LPCTSTR) _szPrefix)) { bStatus = FALSE; } else { szPath = (_szPrefix + L'\\') + szUser; if (! _szSuffix.IsEmpty()) szPath += _szSuffix; bStatus = TRUE; } break; case IDS_USERPROFILE_PATH: if (_szSuffix.IsEmpty()) { bStatus = FALSE; } else { szPath = PROFILE_STR + _szSuffix; bStatus = TRUE; } break; default: bStatus = FALSE; break; } return bStatus; } //+-------------------------------------------------------------------------- // // Member: CRedirPath::GenerateSuffix // // Synopsis: generates a new suffix based on a given path type and folder // // Arguments: [out] szSuffix // [in] cookie // [in] pathType // // Returns: // // History: 3/7/2000 RahulTh created // // Notes: // //--------------------------------------------------------------------------- void CRedirPath::GenerateSuffix (OUT CString & szSuffix, IN UINT cookie, IN UINT pathType ) const { AFX_MANAGE_STATE (AfxGetStaticModuleState()); szSuffix.Empty(); if (IDS_HOMEDIR_PATH == pathType) return; if (IDS_MYPICS == cookie) { // // Use the full My Documents\My Pictures path // only if we are going to the user profile. // Otherwise stick to vanilla My Pictures // This ensures that when My Pictures is redirected independently // to another location, we do not create an extra level of folders // as this might cause security problems for MyDocs if they are // also redirected to the same share. // if (IDS_USERPROFILE_PATH == pathType) szSuffix.LoadString (IDS_MYPICS_RELPATH); else szSuffix.LoadString (IDS_MYPICS); } else szSuffix.LoadString (cookie); // Precede it with a "\" szSuffix = L'\\' + szSuffix; return; } //+-------------------------------------------------------------------------- // // Member: CRedirPath::Load // // Synopsis: parses a given path and breaks it into different components // so that it can be categorized into one of the well known // types // // Arguments: [in] szPath : the given full path // // Returns: TRUE: if the categorization was succesful. // FALSE otherwise // // History: 3/3/2000 RahulTh created // // Notes: // //--------------------------------------------------------------------------- BOOL CRedirPath::Load (IN LPCTSTR pwszPath) { CString szPath; BOOL bStatus = FALSE; szPath = pwszPath; szPath.TrimLeft(); szPath.TrimRight(); szPath.TrimRight (L'\\'); // First check to see if it is a homedir path. bStatus = this->LoadHomedir ((LPCTSTR)szPath); // If not, try per-user if (!bStatus) bStatus = this->LoadPerUser ((LPCTSTR) szPath); // If not, try local userprofile if (!bStatus) bStatus = this->LoadUserprofile ((LPCTSTR) szPath); // // If not try a user defined path. // Note: we cannot use the value blindly here because we need to // make sure that there are no environment variables in there. // if (!bStatus) bStatus = this->LoadSpecific ((LPCTSTR) szPath); return bStatus; } // Determines if a valid path is stored in this object. BOOL CRedirPath::IsPathValid (void) const { return _bDataValid; } // // Determines if the supplied path is different from the path stored in the // object. Note: the suffix is immaterial in these comparisons. // BOOL CRedirPath::IsPathDifferent (IN UINT type, IN LPCTSTR pwszPrefix) const { CString szPrefix; // Make sure that a path has been loaded in this object first. if (! _bDataValid) return TRUE; // If the types of the paths aren't the same, tnen the paths surely aren't if (type != _type) return TRUE; // If we are here, the types of the path are the same // // Comparing the prefix does not make sense for a homedir path or // a userprofile path // if (IDS_USERPROFILE_PATH == type || IDS_HOMEDIR_PATH == type) { return FALSE; } szPrefix = pwszPrefix; szPrefix.TrimLeft(); szPrefix.TrimRight(); szPrefix.TrimRight (L'\\'); if (szPrefix != _szPrefix) return TRUE; else return FALSE; } // parse the path to see if it is a homedir path BOOL CRedirPath::LoadHomedir (LPCTSTR pwszPath) { BOOL bStatus = FALSE; int len, lenHomedir; // Only the My Documents folder is allowed to have a homedir path if (IDS_MYDOCS != _cookie) return FALSE; len = lstrlen (pwszPath); lenHomedir = lstrlen (HOMEDIR_STR); if (lenHomedir <= len && 0 == _wcsnicmp (pwszPath, HOMEDIR_STR, lenHomedir) && (L'\0' == pwszPath[lenHomedir] || L'\\' == pwszPath[lenHomedir]) && NULL == wcsstr (&pwszPath[lenHomedir], L"%") // Variables are not allowed anywhere else ) { bStatus = TRUE; _type = IDS_HOMEDIR_PATH; _szPrefix.Empty(); _szSuffix = &pwszPath[lenHomedir]; } _bDataValid = bStatus; return bStatus; } // parse the path to see if it is a per-user path BOOL CRedirPath::LoadPerUser (LPCTSTR pwszPath) { BOOL bStatus = FALSE; WCHAR * pwszPos = NULL; int lenUsername, len; // Start menu is not allowed to have a per user path. if (IDS_STARTMENU == _cookie) return FALSE; pwszPos = wcsstr (pwszPath, L"%"); if (pwszPos) { *pwszPos = L'\0'; // Temporarily look at only the prefix. if (!IsValidPrefix (IDS_PERUSER_PATH, pwszPath)) { *pwszPos = L'%'; // Reset the character at pwszPos goto LoadPerUser_End; } else { *pwszPos = L'%'; // Reset the character at pwszPos } } // // %username% should be the first variable that appears in the path // if this is to be a per-user path, but it should not be the first // thing in the path // if (NULL != pwszPos && pwszPos != pwszPath) { len = lstrlen (pwszPos); lenUsername = lstrlen (USERNAME_STR); if (lenUsername <= len && 0 == _wcsnicmp (pwszPos, USERNAME_STR, lenUsername) && NULL == wcsstr (&pwszPos[lenUsername], L"%") ) { bStatus = TRUE; _type = IDS_PERUSER_PATH; _szPrefix = pwszPath; _szPrefix = _szPrefix.Left (pwszPos - pwszPath); _szPrefix.TrimLeft(); _szPrefix.TrimRight(); _szPrefix.TrimRight(L'\\'); _szSuffix = &pwszPos[lenUsername]; } } LoadPerUser_End: _bDataValid = bStatus; return bStatus; } // parse the path to see if it is a userprofile path BOOL CRedirPath::LoadUserprofile (LPCTSTR pwszPath) { BOOL bStatus = FALSE; int len, lenUserprofile; len = lstrlen (pwszPath); lenUserprofile = lstrlen (PROFILE_STR); // // Note: it is considered a userprofile path only if it is of the form // %userprofile%\ where does not contain any variables // if (lenUserprofile + 1 < len && 0 == _wcsnicmp (pwszPath, PROFILE_STR, lenUserprofile) && (L'\0' == pwszPath[lenUserprofile] || L'\\' == pwszPath[lenUserprofile]) && NULL == wcsstr (&pwszPath[lenUserprofile], L"%") ) { bStatus = TRUE; _type = IDS_USERPROFILE_PATH; _szPrefix.Empty(); _szSuffix = &pwszPath[lenUserprofile]; } _bDataValid = bStatus; return bStatus; } // parse the path to see if it is a specific path provided by the user BOOL CRedirPath::LoadSpecific (LPCTSTR pwszPath) { BOOL bStatus = FALSE; // We pretty much allow all paths other than empty paths. if (NULL != pwszPath && L'\0' != *pwszPath) { bStatus = TRUE; _type = IDS_SPECIFIC_PATH; _szPrefix = pwszPath; _szPrefix.TrimLeft(); _szPrefix.TrimRight(); _szPrefix.TrimRight(L'\\'); // use X:\ rather than X: to make sure client does not fail if (2 == _szPrefix.GetLength() && L':' == ((LPCTSTR)_szPrefix)[1]) _szPrefix += L'\\'; _szSuffix.Empty(); } _bDataValid = bStatus; return bStatus; } // // Validates the arguments and loads the path into the object. // The existing object is not modified if the data is invalid // BOOL CRedirPath::Load (UINT type, LPCTSTR pwszPrefix, LPCTSTR pwszSuffix) { CString szPrefix; CString szSuffix; // First process the strings. szPrefix = pwszPrefix; szPrefix.TrimLeft(); szPrefix.TrimRight(); szPrefix.TrimRight(L'\\'); szSuffix = pwszSuffix; szSuffix.TrimLeft(); szSuffix.TrimRight(); szSuffix.TrimRight(L'\\'); // // The suffix should never have a variable name in it, except // IDS_SPECIFIC_PATH, for which a suffix really does not make // much sense. // if (IDS_SPECIFIC_PATH != type && -1 != szSuffix.Find (L'%')) { return FALSE; } // Now do the remaining validation on the type and the suffix. switch (type) { case IDS_PERUSER_PATH: if (szPrefix.IsEmpty() || ! IsValidPrefix (type, (LPCTSTR) szPrefix)) return FALSE; break; case IDS_SPECIFIC_PATH: if (!IsValidPrefix (type, (LPCTSTR) szPrefix)) return FALSE; // use X:\ rather than X: to make sure client does not fail. if (2 == szPrefix.GetLength() && L':' == ((LPCTSTR)szPrefix)[1]) szPrefix += L'\\'; szSuffix.Empty(); // The entire path is in the prefix. Suffix does not make sense here. break; case IDS_USERPROFILE_PATH: case IDS_HOMEDIR_PATH: szPrefix.Empty(); // The prefix does not make sense for these paths break; default: return FALSE; break; } // // If we are here, the data is okay. So populate the members. // Note: It is okay for the suffix to be an empty string. // _bDataValid = TRUE; _type = type; _szPrefix = szPrefix; _szSuffix = szSuffix; return TRUE; } void CRedirPath::GetPrefix (OUT CString & szPrefix) const { if (_bDataValid) szPrefix = _szPrefix; else szPrefix.Empty(); } UINT CRedirPath::GetType (void) const { return _type; }