E-MailRelay

gfilestore.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gfilestore.h
19///
20
21#ifndef G_SMTP_FILE_STORE_H
22#define G_SMTP_FILE_STORE_H
23
24#include "gdef.h"
25#include "gmessagestore.h"
26#include "genvelope.h"
27#include "gdatetime.h"
28#include "gexception.h"
29#include "gprocess.h"
30#include "gslot.h"
31#include "groot.h"
32#include "gpath.h"
33#include <fstream>
34#include <memory>
35#include <string>
36
37 namespace GStore
38{
39 class FileStore ;
40 class FileReader ;
41 class FileWriter ;
42 class DirectoryReader ;
43}
44
45//| \class GStore::FileStore
46/// A concrete implementation of the MessageStore interface dealing
47/// in paired flat files.
48///
49/// The implementation puts separate envelope and content files
50/// in the spool directory. The content file is written first.
51/// The presence of a matching envelope file is used to indicate
52/// that the content file is valid and that it has been commited
53/// to the care of the SMTP system for delivery.
54///
55 class GStore::FileStore : public MessageStore
56{
57 public:
58 G_EXCEPTION( InvalidDirectory , tx("invalid spool directory") )
59 G_EXCEPTION( EnvelopeReadError , tx("cannot read envelope file") )
60 G_EXCEPTION( GetError , tx("error getting message") )
61 enum class State // see GStore::FileStore::envelopePath()
62 {
63 New ,
64 Normal ,
65 Locked ,
66 Bad
67 } ;
68 struct Config /// Configuration structure for GStore::FileStore.
69 {
70 std::size_t max_size {0U} ; // zero for unlimited -- passed to GStore::NewFile::ctor
71 unsigned long seq {0UL} ; // sequence number start
72 Config & set_max_size( std::size_t ) noexcept ;
73 Config & set_seq( unsigned long ) noexcept ;
74 } ;
75 struct FileOp /// Low-level file-system operations for GStore::FileStore.
76 {
77 FileOp() = delete ;
78 static int & errno_() noexcept ;
79 static bool rename( const G::Path & , const G::Path & ) ;
80 static bool renameOnto( const G::Path & , const G::Path & ) ;
81 static bool remove( const G::Path & ) noexcept ;
82 static bool exists( const G::Path & ) ;
83 static int fdopen( const G::Path & ) ;
84 static bool hardlink( const G::Path & , const G::Path & ) ;
85 static bool copy( const G::Path & , const G::Path & ) ;
86 static bool copy( const G::Path & , const G::Path & , bool hardlink ) ;
87 static bool mkdir( const G::Path & ) ;
88 static bool isdir( const G::Path & , const G::Path & = {} , const G::Path & = {} ) ;
89 static std::ifstream & openIn( std::ifstream & , const G::Path & ) ;
90 static std::ofstream & openOut( std::ofstream & , const G::Path & ) ;
91 static std::ofstream & openAppend( std::ofstream & , const G::Path & ) ;
92 } ;
93
94 static G::Path defaultDirectory() ;
95 ///< Returns a default spool directory, such as "/var/spool/emailrelay".
96 ///< (Typically with an os-specific implementation.)
97
98 FileStore( const G::Path & spool_dir , const G::Path & delivery_dir , const Config & config ) ;
99 ///< Constructor. Throws an exception if the spool directory
100 ///< is invalid.
101
102 G::Path directory() const ;
103 ///< Returns the spool directory path, as passed in to the
104 ///< constructor.
105
106 G::Path deliveryDir() const ;
107 ///< Returns the base directory for local delivery. Returns
108 ///< directory() by default.
109
110 MessageId newId() ;
111 ///< Hands out a new unique message id.
112
113 static std::unique_ptr<std::ofstream> stream( const G::Path & path ) ;
114 ///< Opens an output stream to a message file using the appropriate
115 ///< effective userid and umask.
116
117 G::Path contentPath( const MessageId & id ) const ;
118 ///< Returns the path for a content file.
119
120 G::Path envelopePath( const MessageId & id , State = State::Normal ) const ;
121 ///< Returns the path for an envelope file.
122
123 static std::string x() ;
124 ///< Returns the prefix for envelope header lines.
125
126 static std::string format( int generation = 0 ) ;
127 ///< Returns an identifier for the storage format implemented
128 ///< by this class, or some older generation of it (eg. -1).
129
130 static bool knownFormat( const std::string & format ) ;
131 ///< Returns true if the storage format string is
132 ///< recognised and supported for reading.
133
134 static Envelope readEnvelope( const G::Path & , std::ifstream * = nullptr ) ;
135 ///< Used by FileStore sibling classes to read an envelope file.
136 ///< Optionally returns the newly-opened stream by reference so
137 ///< that any trailing headers can be read. Throws on error.
138
139 private: // overrides
140 bool empty() const override ;
141 std::string location( const MessageId & ) const override ;
142 std::unique_ptr<StoredMessage> get( const MessageId & ) override ;
143 std::unique_ptr<MessageStore::Iterator> iterator( bool lock ) override ;
144 std::unique_ptr<NewMessage> newMessage( const std::string & , const MessageStore::SmtpInfo & , const std::string & ) override ;
145 void updated() override ;
146 G::Slot::Signal<> & messageStoreUpdateSignal() noexcept override ;
147 G::Slot::Signal<> & messageStoreRescanSignal() noexcept override ;
148 std::vector<MessageId> ids() override ;
149 std::vector<MessageId> failures() override ;
150 void unfailAll() override ;
151 void rescan() override ;
152
153public:
154 ~FileStore() override = default ;
155 FileStore( const FileStore & ) = delete ;
156 FileStore( FileStore && ) = delete ;
157 FileStore & operator=( const FileStore & ) = delete ;
158 FileStore & operator=( FileStore && ) = delete ;
159
160private:
161 static void checkPath( const G::Path & dir ) ;
162 static void osinit() ;
163 G::Path fullPath( const std::string & filename ) const ;
164 std::string getline( std::istream & ) const ;
165 std::string value( const std::string & ) const ;
166 static const std::string & crlf() ;
167 bool emptyCore() const ;
168 void clearAll() ;
169 static MessageId newId( unsigned long ) ;
170
171private:
172 unsigned long m_seq ;
173 G::Path m_dir ;
174 G::Path m_delivery_dir ;
175 const Config m_config ;
176 G::Slot::Signal<> m_update_signal ;
177 G::Slot::Signal<> m_rescan_signal ;
178} ;
179
180//| \class GStore::FileReader
181/// Used by GStore::FileStore, GStore::NewFile and GStore::StoredFile to
182/// claim read permissions for reading a file.
183/// \see G::Root
184///
185 class GStore::FileReader : private G::Root
186{
187 public:
188 FileReader() ;
189 ///< Default constructor. Switches identity for
190 ///< reading a file.
191
192 ~FileReader() ;
193 ///< Destructor. Switches identity back.
194
195 public:
196 FileReader( const FileReader & ) = delete ;
197 FileReader( FileReader && ) = delete ;
198 FileReader & operator=( const FileReader & ) = delete ;
199 FileReader & operator=( FileReader && ) = delete ;
200} ;
201
202//| \class GStore::DirectoryReader
203/// Used by GStore::FileStore, GStore::NewFile and GStore::StoredFile to
204/// claim read permissions for reading a directory.
205/// \see G::Root
206///
207 class GStore::DirectoryReader : private G::Root
208{
209 public:
210 DirectoryReader() ;
211 ///< Default constructor. Switches identity for
212 ///< reading a directory.
213
214 ~DirectoryReader() ;
215 ///< Destructor. Switches identity back.
216
217 public:
218 DirectoryReader( const DirectoryReader & ) = delete ;
219 DirectoryReader( DirectoryReader && ) = delete ;
220 DirectoryReader & operator=( const DirectoryReader & ) = delete ;
221 DirectoryReader & operator=( DirectoryReader && ) = delete ;
222} ;
223
224//| \class GStore::FileWriter
225/// Used by GStore::FileStore, GStore::NewFile and GStore::StoredFile to
226/// claim write permissions.
227/// \see G::Root
228///
229 class GStore::FileWriter : private G::Root , private G::Process::Umask
230{
231 public:
232 FileWriter() ;
233 ///< Default constructor. Switches identity for
234 ///< writing a file.
235
236 ~FileWriter() ;
237 ///< Destructor. Switches identity back.
238
239 public:
240 FileWriter( const FileWriter & ) = delete ;
241 FileWriter( FileWriter && ) = delete ;
242 FileWriter & operator=( const FileWriter & ) = delete ;
243 FileWriter & operator=( FileWriter && ) = delete ;
244} ;
245
246 inline GStore::FileStore::Config & GStore::FileStore::Config::set_max_size( std::size_t n ) noexcept { max_size = n ; return *this ; }
247 inline GStore::FileStore::Config & GStore::FileStore::Config::set_seq( unsigned long n ) noexcept { seq = n ; return *this ; }
248
249#endif
GStore::DirectoryReader
Used by GStore::FileStore, GStore::NewFile and GStore::StoredFile to claim read permissions for readi...
Definition: gfilestore.h:208
GStore::DirectoryReader::DirectoryReader
DirectoryReader()
Default constructor.
GStore::DirectoryReader::~DirectoryReader
~DirectoryReader()
Destructor. Switches identity back.
GStore::Envelope
A structure containing the contents of an envelope file, with support for file reading,...
Definition: genvelope.h:41
GStore::FileReader
Used by GStore::FileStore, GStore::NewFile and GStore::StoredFile to claim read permissions for readi...
Definition: gfilestore.h:186
GStore::FileReader::FileReader
FileReader()
Default constructor.
GStore::FileReader::~FileReader
~FileReader()
Destructor. Switches identity back.
GStore::FileStore
A concrete implementation of the MessageStore interface dealing in paired flat files.
Definition: gfilestore.h:56
GStore::FileStore::deliveryDir
G::Path deliveryDir() const
Returns the base directory for local delivery.
Definition: gfilestore.cpp:124
GStore::FileStore::x
static std::string x()
Returns the prefix for envelope header lines.
Definition: gfilestore.cpp:129
GStore::FileStore::FileStore
FileStore(const G::Path &spool_dir, const G::Path &delivery_dir, const Config &config)
Constructor.
Definition: gfilestore.cpp:109
GStore::FileStore::directory
G::Path directory() const
Returns the spool directory path, as passed in to the constructor.
Definition: gfilestore.cpp:119
GStore::FileStore::newId
MessageId newId()
Hands out a new unique message id.
Definition: gfilestore.cpp:222
GStore::FileStore::envelopePath
G::Path envelopePath(const MessageId &id, State=State::Normal) const
Returns the path for an envelope file.
Definition: gfilestore.cpp:210
GStore::FileStore::stream
static std::unique_ptr< std::ofstream > stream(const G::Path &path)
Opens an output stream to a message file using the appropriate effective userid and umask.
Definition: gfilestore.cpp:198
GStore::FileStore::readEnvelope
static Envelope readEnvelope(const G::Path &, std::ifstream *=nullptr)
Used by FileStore sibling classes to read an envelope file.
Definition: gfilestore.cpp:308
GStore::FileStore::format
static std::string format(int generation=0)
Returns an identifier for the storage format implemented by this class, or some older generation of i...
Definition: gfilestore.cpp:134
GStore::FileStore::contentPath
G::Path contentPath(const MessageId &id) const
Returns the path for a content file.
Definition: gfilestore.cpp:205
GStore::FileStore::knownFormat
static bool knownFormat(const std::string &format)
Returns true if the storage format string is recognised and supported for reading.
Definition: gfilestore.cpp:151
GStore::FileStore::defaultDirectory
static G::Path defaultDirectory()
Returns a default spool directory, such as "/var/spool/emailrelay".
Definition: gfilestore_unix.cpp:30
GStore::FileWriter
Used by GStore::FileStore, GStore::NewFile and GStore::StoredFile to claim write permissions.
Definition: gfilestore.h:230
GStore::FileWriter::~FileWriter
~FileWriter()
Destructor. Switches identity back.
GStore::MessageId
A somewhat opaque identifer for a GStore::MessageStore message id.
Definition: gmessagestore.h:43
GStore::MessageStore
A class which allows SMTP messages to be stored and retrieved.
Definition: gmessagestore.h:73
G::Path
A Path object represents a file system path.
Definition: gpath.h:82
G::Process::Umask
Used to temporarily modify the process umask.
Definition: gprocess.h:197
G::Root
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:52
gdatetime.h
genvelope.h
gexception.h
gmessagestore.h
gpath.h
gprocess.h
groot.h
gslot.h
GStore
Message store classes.
Definition: genvelope.cpp:30
G
Low-level classes.
Definition: garg.h:36
G::tx
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84
std
STL namespace.
GStore::FileStore::Config
Configuration structure for GStore::FileStore.
Definition: gfilestore.h:69
GStore::FileStore::FileOp
Low-level file-system operations for GStore::FileStore.
Definition: gfilestore.h:76
GStore::MessageStore::SmtpInfo
Information on the SMTP options used when submitted.
Definition: gmessagestore.h:84
G::Slot::Signal
A slot holder, with connect() and emit() methods.
Definition: gslot.h:184