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 
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 
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 
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 
192 {
193  m_seq++ ;
194  if( m_seq == 0UL )
195  m_seq++ ;
196  return m_seq ;
197 }
198 
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 
223 {
224  return MessageStore::Iterator( new FileIterator(*this,m_dir,lock,false) ) ;
225 }
226 
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 
262 {
263  G_DEBUG( "GSmtp::FileStore::updated" ) ;
264  bool repoll = m_repoll ;
265  m_repoll = false ;
266  m_signal.emit( repoll ) ;
267 }
268 
270 {
271  return m_signal ;
272 }
273 
275 {
276  m_repoll = true ;
277 }
278 
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 
295 {
296 }
297 
299 {
300 }
301 
302 // ===
303 
305 {
306 }
307 
309 {
310 }
311 
312 // ===
313 
315  G::Root(false) ,
316  G::Process::Umask(G::Process::Umask::Tighter)
317 {
318 }
319 
321 {
322 }
323 
static std::string format()
Returns an identifier for the storage format implemented by this class.
Definition: gfilestore.cpp:115
std::string str() const
Returns the path string.
Definition: gpath.cpp:135
static EpochTime now()
Returns the current epoch time.
Definition: gdatetime.cpp:34
A noncopyable base class (a la boost).
Definition: gnoncopyable.h:35
G::Path contentPath(unsigned long seq) const
Returns the path for a content file.
Definition: gfilestore.cpp:161
SMTP and message-store classes.
static std::string x()
Returns the prefix for envelope header lines.
Definition: gfilestore.cpp:110
FileWriter()
Default constructor.
Definition: gfilestore.cpp:314
virtual void unfailAll()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:279
virtual G::Signal1< bool > & signal()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:269
virtual std::auto_ptr< NewMessage > newMessage(const std::string &from)
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:255
virtual MessageStore::Iterator iterator(bool lock)
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:222
bool more()
Returns true if more and advances by one.
Definition: gdirectory.cpp:110
std::string str() const
Used by GSmtp::FileStore, GSmtp::NewFile and GSmtp::StoredFile to claim read permissions for reading ...
Definition: gfilestore.h:178
Used by GSmtp::FileStore, GSmtp::NewFile and GSmtp::StoredFile to claim write permissions.
Definition: gfilestore.h:194
std::auto_ptr< std::ostream > stream(const G::Path &path)
Returns a stream to the given content.
Definition: gfilestore.cpp:152
~DirectoryReader()
Destructor. Switches identity back.
Definition: gfilestore.cpp:308
A base class for MessageStore::Iterator implementations.
Definition: gmessagestore.h:52
std::auto_ptr< StoredMessage > next()
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
An encapsulation of a file system directory which allows for iterating through the set of contained f...
Definition: gdirectory.h:46
virtual std::auto_ptr< GSmtp::StoredMessage > next()
Definition: gfilestore.cpp:71
FileStore(const G::Path &dir, bool optimise=false, unsigned long max_size=0UL)
Constructor.
Definition: gfilestore.cpp:98
Low-level classes.
A 'body' class for the MessageStore::Iterator 'handle'.
Definition: gfilestore.cpp:50
virtual MessageStore::Iterator failures()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:227
virtual bool empty() const
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:199
#define G_LOG(expr)
Definition: glog.h:98
virtual std::auto_ptr< StoredMessage > get(unsigned long id)
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:232
A concrete derived class implementing the NewMessage interface.
Definition: gnewfile.h:43
A concete derived class implementing the StoredMessage interface.
Definition: gstoredfile.h:45
A Directory iterator that does all file i/o in one go.
Definition: gdirectory.h:164
~FileReader()
Destructor. Switches identity back.
Definition: gfilestore.cpp:298
#define G_DEBUG(expr)
Definition: glog.h:95
static std::string tmp()
A convenience function for constructing a filename for writeable().
~FileWriter()
Destructor. Switches identity back.
Definition: gfilestore.cpp:320
Process-id class.
Definition: gprocess.h:52
A concrete implementation of the MessageStore interface dealing in paired flat files and with an opti...
Definition: gfilestore.h:62
G::Path envelopePath(unsigned long seq) const
Returns the path for an envelope file.
Definition: gfilestore.cpp:166
virtual void updated()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:261
DirectoryReader()
Default constructor.
Definition: gfilestore.cpp:304
static bool knownFormat(const std::string &format)
Returns true if the storage format string is recognised and supported for reading.
Definition: gfilestore.cpp:120
FileIterator(FileStore &store, const G::Path &dir, bool lock, bool failures)
Definition: gfilestore.cpp:63
unsigned long newSeq()
Hands out a new non-zero sequence number.
Definition: gfilestore.cpp:191
virtual void repoll()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:274
A Path object represents a file system path.
Definition: gpath.h:44
FileReader()
Default constructor.
Definition: gfilestore.cpp:294
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
#define G_WARNING(expr)
Definition: glog.h:107
An iterator class for GSmtp::MessageStore.
Definition: gmessagestore.h:62