42 struct DirectoryReader :
private G::Root
45 struct FileDeleter :
private G::Root
48 unsigned long toSize(
const std::string & s )
60 m_allow_delete(allow_delete)
62 if( !accessible( path , by_name?
false:allow_delete ) )
63 throw InvalidDirectory() ;
70 StoreImp::DirectoryReader claim_reader ;
80 bool ok = accessible( iter.
filePath() , allow_delete ) ;
81 G_DEBUG(
"GPop::Store::ctor: [" << iter.
filePath() <<
"]: " << (ok?
"good":
"bad") ) ;
90 G_WARNING(
"GPop::Store::ctor: no sub-directories for pop-by-name found in \"" << path <<
"\": "
91 <<
"create one sub-directory for each authorised pop account" ) ;
96bool GPop::Store::accessible(
const G::Path & dir_path ,
bool for_write )
103 StoreImp::FileDeleter claim_deleter ;
104 ok = dir_test.valid() && dir_test.writeable( tmp_filename ) ;
108 StoreImp::FileReader claim_reader ;
109 ok = dir_test.valid() ;
113 const char * op = for_write ?
"writing" :
"reading" ;
114 G_WARNING(
"GPop::Store: directory not valid for " << op <<
": \"" << dir_path <<
"\"" ) ;
126 return m_allow_delete ;
136GPop::StoreMessage::StoreMessage(
const std::string & name_in , Size size_in ,
bool in_parent_in ) :
139 in_parent(in_parent_in) ,
146 return in_parent ? cpath(sdir) : cpath(edir) ;
151 return G::Path( dir , name+
".content" ) ;
156 return G::Path( edir , name+
".envelope" ) ;
161 return {{},0,
false} ;
164std::string GPop::StoreMessage::uidl()
const
166 return name +
".content" ;
174 m_edir(store.byName()?
G::Path(store.dir(),user):store.dir()) ,
177 G_ASSERT( !user.empty() ) ;
181 StoreImp::DirectoryReader claim_reader ;
183 std::size_t n = iter.
readType( m_edir ,
".envelope" ) ;
184 m_list.reserve( n ) ;
187 std::string ename = iter.
fileName() ;
188 std::string name =
G::Str::head( ename , ename.rfind(
'.') ) ;
189 std::string cname = name +
".content" ;
200 m_list.emplace_back( name , csize , in_parent ) ;
211 m_allow_delete(allow_delete) ,
212 m_edir(store_user.m_edir) ,
213 m_sdir(store_user.m_sdir) ,
214 m_list(store_user.m_list)
220 return m_list.cbegin() ;
225 return m_list.cend() ;
230 std::size_t n = std::count_if( m_list.begin() , m_list.end() ,
233 return static_cast<StoreMessage::Size
>(n) ;
239 for(
const auto & item : m_list )
249 return id >= 1 && id <= static_cast<int>(m_list.size()) && !m_list.at(
id-1).deleted ;
254 G_ASSERT( valid(
id) ) ;
255 return valid(
id) ? m_list.at(
id-1) : StoreMessage::invalid() ;
260 G_ASSERT( valid(
id) ) ;
261 return valid(
id) ? m_list.at(
id-1).size : Size(0) ;
266 G_ASSERT( valid(
id) ) ;
267 if( !valid(
id) )
throw CannotRead( std::to_string(
id) ) ;
269 G::Path cpath = m_list.at(
id-1).cpath(m_edir,m_sdir) ;
270 G_DEBUG(
"GPop::StoreList::get: " <<
id <<
" " << cpath ) ;
272 auto fstream = std::make_unique<std::ifstream>() ;
274 StoreImp::FileReader claim_reader ;
278 if( !fstream->good() )
279 throw CannotRead( cpath.
str() ) ;
287 m_list.at(
id-1).deleted = true ;
293 for(
const auto & item : m_list )
295 if( item.deleted && m_allow_delete )
297 deleteFile( item.epath(m_edir) , all_ok ) ;
299 deleteFile( item.cpath(m_edir,m_sdir) , all_ok ) ;
301 else if( item.deleted )
303 G_DEBUG(
"StoreList::doCommit: not deleting \"" << item.name <<
"\"" ) ;
307 throw CannotDelete() ;
310void GPop::StoreList::deleteFile(
const G::Path & path ,
bool & all_ok )
const
314 StoreImp::FileDeleter claim_deleter ;
317 all_ok = ok && all_ok ;
319 G_ERROR(
"StoreList::deleteFile: failed to delete " << path ) ;
325 G_ASSERT( valid(
id) ) ;
326 return valid(
id) ? m_list.at(
id-1).uidl() : std::string() ;
332 for(
auto & item : m_list )
333 item.deleted = false ;
336bool GPop::StoreList::shared(
const StoreMessage & message )
const
338 if( !message.in_parent )
345 G_DEBUG(
"GPop::StoreList::shared: test sharing of " << message.cpath(m_edir,m_sdir) ) ;
349 G_DEBUG_IF( found ,
"GPop::StoreList::shared: content shared: envelope: " << message.epath(m_sdir) ) ;
354 StoreImp::DirectoryReader claim_reader ;
357 while( iter.
more() && !found )
363 G_DEBUG(
"GPop::StoreList::shared: checking sub-directory: " << sub_dir ) ;
367 G_DEBUG_IF( found ,
"GPop::StoreList::shared: content shared: envelope: " << epath ) ;
369 G_DEBUG_IF( !found ,
"GPop::StoreList::shared: content not shared: no matching envelope" ) ;
375GPop::StoreImp::FileReader::FileReader()
Size messageCount() const
Returns the store's message count.
std::string uidl(int id) const
Returns a message's unique 1-based id.
void rollback()
Rolls back remove()als.
Size byteCount(int id) const
Returns the message size.
bool valid(int id) const
Validates a message id.
StoreList()
Constructor for an empty list.
List::const_iterator cbegin() const
Returns the begin iterator.
std::unique_ptr< std::istream > content(int id) const
Retrieves the message content.
Size totalByteCount() const
Returns the store's total byte count.
void remove(int)
Marks the message files for deletion.
void commit()
Commits remove()als.
List::const_iterator cend() const
Returns the end iterator.
List::value_type get(int id) const
Returns the item with index id-1.
A structure representing a pop message.
Holds the list of messages available to a particular pop user.
StoreUser(Store &, const std::string &user)
Constructor.
bool allowDelete() const
Returns true if files can be deleted.
bool byName() const
Returns true if the spool directory is affected by the user name.
G::Path dir() const
Returns the spool directory path.
Store(const G::Path &spool_dir, bool by_name, bool allow_delete)
Constructor. Throws InvalidDirectory.
A iterator similar to G::DirectoryIterator but doing all file i/o in one go and providing a sorted re...
Path filePath() const
Returns the current path.
std::size_t readAll(const Path &dir)
An initialiser that is to be used after default construction.
bool more()
Returns true if more and advances by one.
std::string fileName() const
Returns the current filename.
std::size_t readType(const Path &dir, string_view suffix, unsigned int limit=0U)
An initialiser that is to be used after default construction.
bool isDir() const
Returns true if the current item is a directory.
An encapsulation of a file system directory that works with G::DirectoryIterator.
static std::string tmp()
A convenience function for constructing a filename for writeable().
static void open(std::ofstream &, const Path &)
Calls open() on the given output file stream.
static std::string sizeString(const Path &file)
Returns the file's size in string format.
static bool remove(const Path &path, std::nothrow_t) noexcept
Deletes the file or directory. Returns false on error.
static bool exists(const Path &file)
Returns true if the file (directory, device etc.) exists.
A Path object represents a file system path.
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
std::string str() const
Returns the path string.
A class which acquires the process's special privileges on construction and releases them on destruct...
static bool isULong(string_view s) noexcept
Returns true if the string can be converted into an unsigned long without throwing an exception.
static unsigned long toULong(string_view s, Limited)
Converts string 's' to an unsigned long.
static std::string head(string_view in, std::size_t pos, string_view default_={})
Returns the first part of the string up to just before the given position.
Overload discrimiator for G::Str::toUWhatever() requesting a range-limited result.