35 struct DirectoryReader ;
71 m_allow_delete(allow_delete)
73 checkPath( path , by_name , allow_delete ) ;
83 return m_allow_delete ;
91void GPop::Store::checkPath(
const G::Path & dir_path ,
bool by_name ,
bool allow_delete )
95 if( !valid(dir_path,
false) )
96 throw InvalidDirectory() ;
110 if( !valid(iter.
filePath(),allow_delete) )
118 G_WARNING(
"GPop::Store: no sub-directories for pop-by-name found in \"" << dir_path <<
"\": "
119 <<
"create one sub-directory for each authorised pop account" ) ;
122 else if( !valid(dir_path,allow_delete) )
124 throw InvalidDirectory() ;
128bool GPop::Store::valid(
const G::Path & dir_path ,
bool allow_delete )
135 FileDeleter claim_deleter ;
136 ok = dir_test.valid() && dir_test.writeable( tmp_filename ) ;
140 FileReader claim_reader ;
141 ok = dir_test.valid() ;
145 const char * op = allow_delete ?
"writing" :
"reading" ;
146 G_WARNING(
"GPop::Store: directory not valid for " << op <<
": \"" << dir_path <<
"\"" ) ;
153GPop::StoreLock::File::File(
const G::Path & content_path ) :
154 name(content_path.basename()) ,
155 size(toSize(
G::File::sizeString(content_path.str())))
159GPop::StoreLock::File::File(
const std::string & content_name ,
const std::string & size_string ) :
161 size(toSize(size_string))
165bool GPop::StoreLock::File::operator<(
const File & rhs )
const
167 return name < rhs.name ;
170GPop::StoreLock::Size GPop::StoreLock::File::toSize(
const std::string & s )
184 G_ASSERT( ! locked() ) ;
185 G_ASSERT( ! user.empty() ) ;
186 G_ASSERT( m_store !=
nullptr ) ;
189 m_dir = m_store->dir() ;
190 if( m_store->byName() )
191 m_dir.pathAppend( user ) ;
197 iter.
readType( m_dir ,
".envelope" ) ;
200 File file( contentPath(iter.
fileName()) ) ;
201 m_initial.insert( file ) ;
208 std::size_t limit = m_initial.size() * 1000U ;
209 for( std::size_t i = 0U ; i < limit ; i++ )
211 std::ostringstream ss ;
212 ss <<
"dummy." << i <<
".content" ;
213 m_initial.insert( File(ss.str()) ) ;
218 m_current = m_initial ;
220 G_ASSERT( locked() ) ;
225 return m_store !=
nullptr && ! m_user.empty() ;
233 G_ASSERT( locked() ) ;
234 return static_cast<Size
>(m_current.size()) ;
239 G_ASSERT( locked() ) ;
241 for(
const auto & item : m_current )
248 G_ASSERT( locked() ) ;
249 return id >= 1 && id <= static_cast<int>(m_initial.size()) ;
252GPop::StoreLock::Set::iterator GPop::StoreLock::find(
int id )
254 G_ASSERT( valid(
id) ) ;
255 auto initial_p = m_initial.begin() ;
256 for(
int i = 1 ; i <
id && initial_p != m_initial.end() ; i++ , ++initial_p ) ;
260GPop::StoreLock::Set::const_iterator GPop::StoreLock::find(
int id )
const
262 G_ASSERT( valid(
id) ) ;
263 auto initial_p = m_initial.begin() ;
264 for(
int i = 1 ; i <
id && initial_p != m_initial.end() ; i++ , ++initial_p ) ;
268GPop::StoreLock::Set::iterator GPop::StoreLock::find(
const std::string & name )
270 auto current_p = m_current.begin() ;
271 for( ; current_p != m_current.end() ; ++current_p )
273 if( (*current_p).name == name )
281 G_ASSERT( locked() ) ;
282 return (*find(
id)).size ;
287 G_ASSERT( locked() ) ;
290 for(
auto p = m_current.begin() ; p != m_current.end() ; ++p , i++ )
292 if(
id == -1 ||
id == i )
293 list.push_back(
Entry(i,(*p).size,(*p).name) ) ;
300 G_ASSERT( locked() ) ;
301 G_ASSERT( valid(
id) ) ;
303 G_DEBUG(
"GPop::StoreLock::get: " <<
id <<
": " << path(
id) ) ;
305 auto file = std::make_unique<std::ifstream>() ;
306 G::Path file_path = path(
id ) ;
313 throw CannotRead( file_path.
str() ) ;
315 return std::unique_ptr<std::istream>( file.release() ) ;
320 G_ASSERT( locked() ) ;
321 G_ASSERT( valid(
id) ) ;
323 auto initial_p = find(
id ) ;
324 auto current_p = find( (*initial_p).name ) ;
325 if( current_p != m_current.end() )
327 m_deleted.insert( *initial_p ) ;
328 m_current.erase( current_p ) ;
334 G_ASSERT( locked() ) ;
337 Store * store = m_store ;
344void GPop::StoreLock::doCommit(
Store & store )
const
347 for(
const auto & item : m_deleted )
351 deleteFile( envelopePath(item) , all_ok ) ;
352 if( unlinked(store,item) )
353 deleteFile( contentPath(item) , all_ok ) ;
357 G_DEBUG(
"StoreLock::doCommit: not deleting \"" << item.name <<
"\"" ) ;
361 throw CannotDelete() ;
364void GPop::StoreLock::deleteFile(
const G::Path & path ,
bool & all_ok )
const
368 FileDeleter claim_deleter ;
371 all_ok = ok && all_ok ;
373 G_ERROR(
"StoreLock::remove: failed to delete " << path ) ;
378 G_ASSERT( valid(
id) ) ;
379 auto p = find(
id ) ;
383G::Path GPop::StoreLock::path(
int id )
const
385 G_ASSERT( valid(
id) ) ;
386 auto p = find(
id ) ;
387 const File & file = (*p) ;
388 return contentPath( file ) ;
391G::Path GPop::StoreLock::path(
const std::string & filename ,
bool fallback )
const
401 return ( fallback && !
G::File::exists(path_1,std::nothrow) ) ? path_2 : path_1 ;
404std::string GPop::StoreLock::envelopeName(
const std::string & content_name )
const
406 std::string filename = content_name ;
411std::string GPop::StoreLock::contentName(
const std::string & envelope_name )
const
413 std::string filename = envelope_name ;
418G::Path GPop::StoreLock::contentPath(
const std::string & envelope_name )
const
420 const bool try_parent_directory = true ;
421 return path( contentName(envelope_name) , try_parent_directory ) ;
424G::Path GPop::StoreLock::contentPath(
const File & file )
const
426 const bool try_parent_directory = true ;
427 return path( file.name , try_parent_directory ) ;
430G::Path GPop::StoreLock::envelopePath(
const File & file )
const
432 const bool try_parent_directory = false ;
433 return path( envelopeName(file.name) , try_parent_directory ) ;
438 G_ASSERT( locked() ) ;
440 m_current = m_initial ;
443bool GPop::StoreLock::unlinked(
Store & store ,
const File & file )
const
447 G_DEBUG(
"StoreLock::unlinked: unlinked since not pop-by-name: " << file.name ) ;
451 G::Path normal_content_path = m_dir ; normal_content_path.
pathAppend( file.name ) ;
454 G_DEBUG(
"StoreLock::unlinked: unlinked since in its own directory: " << normal_content_path ) ;
463 DirectoryReader claim_reader ;
468 if( ! iter.
isDir() ) continue ;
469 G_DEBUG(
"Store::unlinked: checking sub-directory: " << iter.
fileName() ) ;
473 G_DEBUG(
"StoreLock::unlinked: still in use: envelope exists: " << envelope_path ) ;
482 G_DEBUG(
"StoreLock::unlinked: unlinked since no envelope found in any sub-directory" ) ;
489GPop::FileReader::FileReader()
Represents a file in the GPop::Store.
Size byteCount(int id) const
Returns a message size.
bool valid(int id) const
Validates a message number.
std::string uidl(int id) const
Returns a message's unique id.
std::unique_ptr< std::istream > get(int id) const
Retrieves the message content.
List list(int id=-1) const
Lists messages in the store.
void rollback()
Rolls back remove()als but retains the lock.
void commit()
Commits remove()als.
void lock(const std::string &user)
Initialisation.
StoreLock(Store &store)
Constructor.
Size messageCount() const
Returns the store's message count.
void remove(int)
Marks the message for removal.
Size totalByteCount() const
Returns the store's total byte count.
bool locked() const
Returns true if locked.
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.
A iterator similar to G::DirectoryIterator but doing all file i/o in one go.
Path filePath() const
Returns the current path.
void readType(const Path &dir, const std::string &suffix, unsigned int limit=0U)
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.
void readAll(const Path &dir)
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 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.
void pathAppend(const std::string &tail)
Appends a filename or a relative path to this path.
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 unsigned long toULong(const std::string &s, Limited)
Converts string 's' to an unsigned long.
static bool replace(std::string &s, const std::string &from, const std::string &to, std::size_t *pos_p=nullptr)
Replaces 'from' with 'to', starting at offset '*pos_p'.
static bool enabled() noexcept
Returns true if test features are enabled.
A trivial class which is used like G::Root by GPop::Store for reading directory listings.
A trivial specialisation of G::Root used by GPop::Store for deleting files.
A trivial class which is used like G::Root by GPop::Store for reading files.
Overload discrimiator for G::Str::toUWhatever() requesting a range-limited result.