- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gfilestore.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // gfilestore.cpp
19 //
20
21 #include "gdef.h"
22 #include "gsmtp.h"
23 #include "gnoncopyable.h"
24 #include "gfilestore.h"
25 #include "gnewfile.h"
26 #include "gstoredfile.h"
27 #include "gprocess.h"
28 #include "gdirectory.h"
29 #include "groot.h"
30 #include "gmemory.h"
31 #include "gpath.h"
32 #include "gfile.h"
33 #include "gstr.h"
34 #include "glog.h"
35 #include "gassert.h"
36 #include <iostream>
37 #include <fstream>
38
39 namespace GSmtp
40 {
41 class FileIterator ;
42 }
43
50 class GSmtp::FileIterator : public GSmtp::MessageStore::IteratorImp , public G::noncopyable
51 {
52 public:
53 FileIterator( FileStore & store , const G::Path & dir , bool lock , bool failures ) ;
54 virtual std::auto_ptr<GSmtp::StoredMessage> next() ;
55 private:
56 FileStore & m_store ;
57 G::DirectoryList m_iter ;
58 bool m_lock ;
59 } ;
60
61 // ===
62
63 GSmtp::FileIterator::FileIterator( FileStore & store , const G::Path & dir , bool lock , bool failures ) :
64 m_store(store) ,
65 m_lock(lock)
66 {
67 DirectoryReader claim_reader ;
68 m_iter.readType( dir , std::string(failures?".envelope.bad":".envelope") ) ;
69 }
70
71 std::auto_ptr<GSmtp::StoredMessage> GSmtp::FileIterator::next()
72 {
73 while( m_iter.more() )
74 {
75 std::auto_ptr<StoredFile> m( new StoredFile(m_store,m_iter.filePath()) ) ;
76 if( m_lock && !m->lock() )
77 {
78 G_WARNING( "GSmtp::MessageStore: cannot lock file: \"" << m_iter.filePath() << "\"" ) ;
79 continue ;
80 }
81
82 std::string reason ;
83 const bool check = m_lock ; // check for no-remote-recipients
84 bool ok = m->readEnvelope(reason,check) && m->openContent(reason) ;
85 if( ok )
86 return std::auto_ptr<StoredMessage>( m.release() ) ;
87
88 if( m_lock )
89 m->fail( reason , 0 ) ;
90 else
91 G_WARNING( "GSmtp::MessageStore: ignoring \"" << m_iter.filePath() << "\": " << reason ) ;
92 }
93 return std::auto_ptr<StoredMessage>(NULL) ;
94 }
95
96 // ===
97
98 GSmtp::FileStore::FileStore( const G::Path & dir , bool optimise , unsigned long max_size ) :
99 m_seq(1UL) ,
100 m_dir(dir) ,
101 m_optimise(optimise) ,
102 m_empty(false) ,
103 m_repoll(false) ,
104 m_max_size(max_size)
105 {
106 m_pid_modifier = static_cast<unsigned long>(G::DateTime::now()) % 1000000UL ;
107 checkPath( dir ) ;
108 }
109
110 std::string GSmtp::FileStore::x()
111 {
112 return "X-MailRelay-" ;
113 }
114
115 std::string GSmtp::FileStore::format()
116 {
117 return "#2821.4" ; // new for 1.9
118 }
119
120 bool GSmtp::FileStore::knownFormat( const std::string & format )
121 {
122 return format == "#2821.3" || format == "#2821.4" ;
123 }
124
125 void GSmtp::FileStore::checkPath( const G::Path & directory_path )
126 {
127 G::Directory dir_test( directory_path ) ;
128 bool ok = false ;
129
130 // fail if not readable (after switching effective userid)
131 {
132 FileWriter claim_writer ;
133 ok = dir_test.valid() ;
134 }
135 if( !ok )
136 {
137 throw InvalidDirectory( directory_path.str() ) ;
138 }
139
140 // warn if not writeable (after switching effective userid)
141 {
142 std::string tmp = G::Directory::tmp() ;
143 FileWriter claim_writer ;
144 ok = dir_test.writeable(tmp) ;
145 }
146 if( !ok )
147 {
148 G_WARNING( "GSmtp::MessageStore: directory not writable: \"" << directory_path << "\"" ) ;
149 }
150 }
151
152 std::auto_ptr<std::ostream> GSmtp::FileStore::stream( const G::Path & path )
153 {
154 FileWriter claim_writer ;
155 std::auto_ptr<std::ostream> ptr(
156 new std::ofstream( path.str().c_str() ,
157 std::ios_base::binary | std::ios_base::out | std::ios_base::trunc ) ) ;
158 return ptr ;
159 }
160
161 G::Path GSmtp::FileStore::contentPath( unsigned long seq ) const
162 {
163 return fullPath( filePrefix(seq) + ".content" ) ;
164 }
165
166 G::Path GSmtp::FileStore::envelopePath( unsigned long seq ) const
167 {
168 return fullPath( filePrefix(seq) + ".envelope" ) ;
169 }
170
171 G::Path GSmtp::FileStore::envelopeWorkingPath( unsigned long seq ) const
172 {
173 return fullPath( filePrefix(seq) + ".envelope.new" ) ;
174 }
175
176 std::string GSmtp::FileStore::filePrefix( unsigned long seq ) const
177 {
178 std::ostringstream ss ;
179 G::Process::Id pid ;
180 ss << "emailrelay." << pid.str() << "." << m_pid_modifier << "." << seq ;
181 return ss.str() ;
182 }
183
184 G::Path GSmtp::FileStore::fullPath( const std::string & filename ) const
185 {
186 G::Path p( m_dir ) ;
187 p.pathAppend( filename ) ;
188 return p ;
189 }
190
191 unsigned long GSmtp::FileStore::newSeq()
192 {
193 m_seq++ ;
194 if( m_seq == 0UL )
195 m_seq++ ;
196 return m_seq ;
197 }
198
199 bool GSmtp::FileStore::empty() const
200 {
201 if( m_optimise )
202 {
203 if( !m_empty )
204 const_cast<FileStore*>(this)->m_empty = emptyCore() ;
205 return m_empty ;
206 }
207 else
208 {
209 return emptyCore() ;
210 }
211 }
212
213 bool GSmtp::FileStore::emptyCore() const
214 {
215 G::DirectoryList list ;
216 DirectoryReader claim_reader ;
217 list.readType( m_dir , ".envelope" , 1U ) ;
218 const bool no_more = !list.more() ;
219 return no_more ;
220 }
221
222 GSmtp::MessageStore::Iterator GSmtp::FileStore::iterator( bool lock )
223 {
224 return MessageStore::Iterator( new FileIterator(*this,m_dir,lock,false) ) ;
225 }
226
227 GSmtp::MessageStore::Iterator GSmtp::FileStore::failures()
228 {
229 return MessageStore::Iterator( new FileIterator(*this,m_dir,false,true) ) ;
230 }
231
232 std::auto_ptr<GSmtp::StoredMessage> GSmtp::FileStore::get( unsigned long id )
233 {
234 G::Path path = envelopePath( id ) ;
235
236 std::auto_ptr<StoredFile> message( new StoredFile(*this,path) ) ;
237
238 if( ! message->lock() )
239 throw GetError( path.str() + ": cannot lock the file" ) ;
240
241 std::string reason ;
242 const bool check = false ; // don't check for no-remote-recipients
243 if( ! message->readEnvelope(reason,check) )
244 throw GetError( path.str() + ": cannot read the envelope: " + reason ) ;
245
246 if( ! message->openContent(reason) )
247 throw GetError( path.str() + ": cannot read the content: " + reason ) ;
248
249 G_LOG( "GSmtp::FileStore::get: processing message \"" << message->name() << "\"" ) ;
250
251 std::auto_ptr<StoredMessage> message_base_ptr( message.release() ) ; // up-cast
252 return message_base_ptr ;
253 }
254
255 std::auto_ptr<GSmtp::NewMessage> GSmtp::FileStore::newMessage( const std::string & from )
256 {
257 m_empty = false ;
258 return std::auto_ptr<NewMessage>( new NewFile(from,*this,m_max_size) ) ;
259 }
260
261 void GSmtp::FileStore::updated()
262 {
263 G_DEBUG( "GSmtp::FileStore::updated" ) ;
264 bool repoll = m_repoll ;
265 m_repoll = false ;
266 m_signal.emit( repoll ) ;
267 }
268
269 G::Signal1<bool> & GSmtp::FileStore::signal()
270 {
271 return m_signal ;
272 }
273
274 void GSmtp::FileStore::repoll()
275 {
276 m_repoll = true ;
277 }
278
279 void GSmtp::FileStore::unfailAll()
280 {
281 MessageStore::Iterator iter( failures() ) ;
282 for(;;)
283 {
284 std::auto_ptr<StoredMessage> message = iter.next() ;
285 if( message.get() == NULL )
286 break ;
287 G_DEBUG( "GSmtp::FileStore::unfailAll: " << message->name() ) ;
288 message->unfail() ;
289 }
290 }
291
292 // ===
293
294 GSmtp::FileReader::FileReader()
295 {
296 }
297
298 GSmtp::FileReader::~FileReader()
299 {
300 }
301
302 // ===
303
304 GSmtp::DirectoryReader::DirectoryReader()
305 {
306 }
307
308 GSmtp::DirectoryReader::~DirectoryReader()
309 {
310 }
311
312 // ===
313
314 GSmtp::FileWriter::FileWriter() :
315 G::Root(false) ,
316 G::Process::Umask(G::Process::Umask::Tighter)
317 {
318 }
319
320 GSmtp::FileWriter::~FileWriter()
321 {
322 }
323
GSmtp::FileStore::format
static std::string format()
Returns an identifier for the storage format implemented by this class.
Definition: gfilestore.cpp:115
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.cpp:135
G::DateTime::now
static EpochTime now()
Returns the current epoch time.
Definition: gdatetime.cpp:34
G::noncopyable
A noncopyable base class (a la boost).
Definition: gnoncopyable.h:35
gdirectory.h
GSmtp::FileStore::contentPath
G::Path contentPath(unsigned long seq) const
Returns the path for a content file.
Definition: gfilestore.cpp:161
GSmtp
SMTP and message-store classes.
GSmtp::FileStore::x
static std::string x()
Returns the prefix for envelope header lines.
Definition: gfilestore.cpp:110
GSmtp::FileWriter::FileWriter
FileWriter()
Default constructor.
Definition: gfilestore.cpp:314
GSmtp::FileStore::unfailAll
virtual void unfailAll()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:279
glog.h
GSmtp::FileStore::signal
virtual G::Signal1< bool > & signal()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:269
GSmtp::FileStore::newMessage
virtual std::auto_ptr< NewMessage > newMessage(const std::string &from)
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:255
GSmtp::FileStore::iterator
virtual MessageStore::Iterator iterator(bool lock)
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:222
G::DirectoryList::more
bool more()
Returns true if more and advances by one.
Definition: gdirectory.cpp:110
G::Process::Id::str
std::string str() const
Definition: gprocess_unix.cpp:236
GSmtp::DirectoryReader
Used by GSmtp::FileStore, GSmtp::NewFile and GSmtp::StoredFile to claim read permissions for reading ...
Definition: gfilestore.h:178
G::Signal1< bool >
groot.h
GSmtp::FileWriter
Used by GSmtp::FileStore, GSmtp::NewFile and GSmtp::StoredFile to claim write permissions.
Definition: gfilestore.h:194
GSmtp::FileStore::stream
std::auto_ptr< std::ostream > stream(const G::Path &path)
Returns a stream to the given content.
Definition: gfilestore.cpp:152
GSmtp::DirectoryReader::~DirectoryReader
~DirectoryReader()
Destructor. Switches identity back.
Definition: gfilestore.cpp:308
GSmtp::MessageStore::IteratorImp
A base class for MessageStore::Iterator implementations.
Definition: gmessagestore.h:52
GSmtp::MessageStore::Iterator::next
std::auto_ptr< StoredMessage > next()
Definition: gmessagestore.cpp:55
G::DirectoryList::readType
void readType(const Path &dir, const std::string &suffix, unsigned int limit=0U)
An initialiser that is to be used after default construction.
Definition: gdirectory.cpp:87
G::Directory
An encapsulation of a file system directory which allows for iterating through the set of contained f...
Definition: gdirectory.h:46
GSmtp::FileIterator::next
virtual std::auto_ptr< GSmtp::StoredMessage > next()
Definition: gfilestore.cpp:71
gstr.h
gfilestore.h
gassert.h
GSmtp::FileStore::FileStore
FileStore(const G::Path &dir, bool optimise=false, unsigned long max_size=0UL)
Constructor.
Definition: gfilestore.cpp:98
G
Low-level classes.
GSmtp::FileIterator
A 'body' class for the MessageStore::Iterator 'handle'.
Definition: gfilestore.cpp:50
GSmtp::FileStore::failures
virtual MessageStore::Iterator failures()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:227
GSmtp::FileStore::empty
virtual bool empty() const
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:199
G_LOG
#define G_LOG(expr)
Definition: glog.h:98
GSmtp::FileStore::get
virtual std::auto_ptr< StoredMessage > get(unsigned long id)
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:232
gfile.h
gprocess.h
GSmtp::NewFile
A concrete derived class implementing the NewMessage interface.
Definition: gnewfile.h:43
GSmtp::StoredFile
A concete derived class implementing the StoredMessage interface.
Definition: gstoredfile.h:45
G::DirectoryList
A Directory iterator that does all file i/o in one go.
Definition: gdirectory.h:164
GSmtp::FileReader::~FileReader
~FileReader()
Destructor. Switches identity back.
Definition: gfilestore.cpp:298
G_DEBUG
#define G_DEBUG(expr)
Definition: glog.h:95
G::Directory::tmp
static std::string tmp()
A convenience function for constructing a filename for writeable().
Definition: gdirectory_unix.cpp:69
gstoredfile.h
gnoncopyable.h
GSmtp::FileWriter::~FileWriter
~FileWriter()
Destructor. Switches identity back.
Definition: gfilestore.cpp:320
G::Process::Id
Process-id class.
Definition: gprocess.h:52
gpath.h
GSmtp::FileStore
A concrete implementation of the MessageStore interface dealing in paired flat files and with an opti...
Definition: gfilestore.h:62
GSmtp::FileStore::envelopePath
G::Path envelopePath(unsigned long seq) const
Returns the path for an envelope file.
Definition: gfilestore.cpp:166
GSmtp::FileStore::updated
virtual void updated()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:261
GSmtp::DirectoryReader::DirectoryReader
DirectoryReader()
Default constructor.
Definition: gfilestore.cpp:304
gsmtp.h
GSmtp::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:120
GSmtp::FileIterator::FileIterator
FileIterator(FileStore &store, const G::Path &dir, bool lock, bool failures)
Definition: gfilestore.cpp:63
gnewfile.h
GSmtp::FileStore::newSeq
unsigned long newSeq()
Hands out a new non-zero sequence number.
Definition: gfilestore.cpp:191
gmemory.h
GSmtp::FileStore::repoll
virtual void repoll()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:274
G::Path
A Path object represents a file system path.
Definition: gpath.h:44
GSmtp::FileReader::FileReader
FileReader()
Default constructor.
Definition: gfilestore.cpp:294
GSmtp::FileStore::envelopeWorkingPath
G::Path envelopeWorkingPath(unsigned long seq) const
Returns the path for an envelope file which is in the process of being written.
Definition: gfilestore.cpp:171
G_WARNING
#define G_WARNING(expr)
Definition: glog.h:107
GSmtp::MessageStore::Iterator
An iterator class for GSmtp::MessageStore.
Definition: gmessagestore.h:62