45 struct DirectoryReader :
private G::Root
48 struct DirectoryCreator :
private G::Root
52 struct FileDeleter :
private G::Root
55 unsigned long toSize(
const std::string & s )
69 if( !accessible( path , m_config.by_name ?
false : m_config.allow_delete ) )
70 throw InvalidDirectory() ;
73 if( m_config.by_name )
77 StoreImp::DirectoryReader claim_reader ;
82 if( !accessible( list.
filePath() , m_config.allow_delete ) )
84 G_WARNING(
"GPop::Store::ctor: pop-by-name sub-directory [" << list.
fileName() <<
"] is not accessible" ) ;
92 if( m_config.by_name && m_config.by_name_mkdir )
94 bool created = false ;
99 StoreImp::DirectoryCreator claim_root ;
105 G_LOG(
"GPop::Store::prepare: created pop-by-name sub-directory [" << user <<
"]" ) ;
109 G_WARNING(
"GPop::Store::prepare: failed to create pop-by-name sub-directory "
115bool GPop::Store::accessible(
const G::Path & dir_path ,
bool for_write )
122 StoreImp::FileDeleter claim_deleter ;
123 ok = dir_test.valid() && dir_test.writeable( tmp_filename ) ;
127 StoreImp::FileReader claim_reader ;
128 ok = dir_test.valid() ;
132 const char * op = for_write ?
"writing" :
"reading" ;
133 G_WARNING(
"GPop::Store: directory not valid for " << op <<
": \"" << dir_path <<
"\"" ) ;
145 return m_config.allow_delete ;
150 return m_config.by_name ;
155GPop::StoreMessage::StoreMessage(
const std::string & name_in , Size size_in ,
bool in_parent_in ) :
158 in_parent(in_parent_in)
164 return in_parent ? cpath(sdir) : cpath(edir) ;
169 return G::Path( dir , name+
".content" ) ;
174 return G::Path( edir , name+
".envelope" ) ;
179 return {{},0,
false} ;
182std::string GPop::StoreMessage::uidl()
const
184 return name +
".content" ;
192 m_edir(store.byName()?
G::Path(store.dir(),user):store.dir()) ,
195 G_ASSERT( !user.empty() ) ;
199 StoreImp::DirectoryReader claim_reader ;
201 std::size_t n = iter.
readType( m_edir ,
".envelope" ) ;
202 m_list.reserve( n ) ;
205 std::string ename = iter.
fileName() ;
206 std::string name =
G::Str::head( ename , ename.rfind(
'.') ) ;
207 std::string cname = name +
".content" ;
218 m_list.emplace_back( name , csize , in_parent ) ;
229 m_allow_delete(allow_delete) ,
230 m_edir(store_user.m_edir) ,
231 m_sdir(store_user.m_sdir) ,
232 m_list(store_user.m_list)
238 return m_list.cbegin() ;
243 return m_list.cend() ;
248 std::size_t n = std::count_if( m_list.begin() , m_list.end() ,
251 return static_cast<StoreMessage::Size
>(n) ;
257 for(
const auto & item : m_list )
267 std::size_t offset =
static_cast<std::size_t
>(id) - 1U ;
268 return id >= 1 && offset < m_list.size() && !m_list.at(offset).deleted ;
273 G_ASSERT( valid(
id) ) ;
274 std::size_t offset =
static_cast<std::size_t
>(id) - 1U ;
275 return valid(
id) ? m_list.at(offset) : StoreMessage::invalid() ;
280 G_ASSERT( valid(
id) ) ;
281 std::size_t offset =
static_cast<std::size_t
>(id) - 1U ;
282 return valid(
id) ? m_list.at(offset).size : Size(0) ;
287 G_ASSERT( valid(
id) ) ;
289 throw CannotRead( std::to_string(
id) ) ;
291 std::size_t offset =
static_cast<std::size_t
>(id) - 1U ;
292 G::Path cpath = m_list.at(offset).cpath(m_edir,m_sdir) ;
293 G_DEBUG(
"GPop::StoreList::get: " <<
id <<
" " << cpath ) ;
295 auto fstream = std::make_unique<std::ifstream>() ;
297 StoreImp::FileReader claim_reader ;
301 if( !fstream->good() )
302 throw CannotRead( cpath.
str() ) ;
311 std::size_t offset =
static_cast<std::size_t
>(id) - 1U ;
312 m_list.at(offset).deleted = true ;
319 for(
const auto & item : m_list )
321 if( item.deleted && m_allow_delete )
323 deleteFile( item.epath(m_edir) , all_ok ) ;
325 deleteFile( item.cpath(m_edir,m_sdir) , all_ok ) ;
327 else if( item.deleted )
329 G_DEBUG(
"StoreList::doCommit: not deleting \"" << item.name <<
"\"" ) ;
333 throw CannotDelete() ;
336void GPop::StoreList::deleteFile(
const G::Path & path ,
bool & all_ok )
const
340 StoreImp::FileDeleter claim_deleter ;
343 all_ok = ok && all_ok ;
345 G_ERROR(
"StoreList::deleteFile: failed to delete " << path ) ;
351 G_ASSERT( valid(
id) ) ;
352 std::size_t offset =
static_cast<std::size_t
>(id) - 1U ;
353 return valid(
id) ? m_list.at(offset).uidl() : std::string() ;
359 for(
auto & item : m_list )
360 item.deleted = false ;
363bool GPop::StoreList::shared(
const StoreMessage & message )
const
365 if( !message.in_parent )
372 G_DEBUG(
"GPop::StoreList::shared: test sharing of " << message.cpath(m_edir,m_sdir) ) ;
376 G_DEBUG_IF( found ,
"GPop::StoreList::shared: content shared: envelope: " << message.epath(m_sdir) ) ;
381 StoreImp::DirectoryReader claim_reader ;
384 while( iter.
more() && !found )
390 G_DEBUG(
"GPop::StoreList::shared: checking sub-directory: " << sub_dir ) ;
394 G_DEBUG_IF( found ,
"GPop::StoreList::shared: content shared: envelope: " << epath ) ;
396 G_DEBUG_IF( !found ,
"GPop::StoreList::shared: content not shared: no matching envelope" ) ;
402GPop::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.
void prepare(const std::string &user)
Prepares the store for the newly-authenticated user.
bool byName() const
Returns true if the spool directory is affected by the user name.
Store(const G::Path &spool_dir, const Config &)
Constructor. Throws InvalidDirectory.
G::Path dir() const
Returns the spool directory path.
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, std::string_view suffix, unsigned int limit=0U)
An initialiser that is to be used after default construction.
std::size_t readDirectories(const Path &dir, unsigned int limit=0U)
An initialiser that reads all sub-directories.
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.
static bool mkdir(const Path &dir, std::nothrow_t)
Creates a directory.
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.
Used to temporarily modify the process umask.
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
A class which acquires the process's special privileges on construction and releases them on destruct...
static bool isPrintable(std::string_view s) noexcept
Returns true if every character is 0x20 or above but not 0x7f.
static bool isULong(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned long without throwing an exception.
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
static unsigned long toULong(std::string_view s, Limited)
Converts string 's' to an unsigned long.
static std::string head(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the first part of the string up to just before the given position.
Configuration structure for GPop::Store.
Overload discrimiator for G::Str::toUWhatever() requesting a range-limited result.