filter.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 // filter.cpp
19 //
20 // Provides filter_run(), filter_main() and filter_help().
21 //
22 
23 #include "gdef.h"
24 #include "garg.h"
25 #include "gfile.h"
26 #include "gstr.h"
27 #include "gexception.h"
28 #include "gdirectory.h"
29 #include "legal.h"
30 #include "filter.h"
31 #include <iostream>
32 #include <exception>
33 #include <stdexcept>
34 #include <sstream>
35 #include <list>
36 #include <string>
37 
38 G_EXCEPTION( FilterError , "filter error" ) ;
39 
40 void filter_help( const std::string & prefix )
41 {
42  std::cout
43  << "usage: " << prefix << " <emailrelay-content-file>" << std::endl
44  << std::endl
45  << "Copies the corresponding emailrelay envelope file into all " << std::endl
46  << "subdirectories of the spool directory. Exits with a " << std::endl
47  << "value of 100 if copied once or more. Intended for use " << std::endl
48  << "with \"emailrelay --pop-by-name\"." << std::endl
49  << std::endl
50  << Main::Legal::warranty(std::string(),"\n") << std::endl
51  << Main::Legal::copyright() << std::endl ;
52 }
53 
54 bool filter_run( const std::string & content )
55 {
56  // check the content file exists
57  //
58  G::Path content_path( content ) ;
59  bool ok = G::File::exists( content_path ) ;
60  if( !ok )
61  throw FilterError( "no such file" ) ;
62 
63  // build the envelope name
64  //
65  G::Path dir_path = content_path.dirname() ;
66  std::string envelope_name = content_path.basename() ;
67  unsigned int n = G::Str::replaceAll( envelope_name , "content" , "envelope" ) ;
68  if( n != 1U )
69  throw FilterError( "invalid filename" ) ;
70 
71  // check the envelope file exists
72  //
73  G::Path envelope_path = G::Path( dir_path , envelope_name + ".new" ) ;
74  if( ! G::File::exists(envelope_path) )
75  {
76  // fall back to no ".new" extension in case we are run manually for some reason
77  G::Path envelope_path_alt = G::Path( dir_path , envelope_name ) ;
78  if( G::File::exists(envelope_path_alt) )
79  envelope_path = envelope_path_alt ;
80  else
81  throw FilterError( std::string() + "no envelope file \"" + envelope_path.str() + "\"" ) ;
82  }
83 
84  // read the content "to" address
85  std::string to = filter_read_to( content_path.str() ) ;
86 
87  // copy the envelope into all sub-directories
88  //
89  int directory_count = 0 ;
90  std::list<std::string> failures ;
91  G::Directory dir( dir_path ) ;
92  G::DirectoryIterator iter( dir ) ;
93  while( iter.more() && !iter.error() )
94  {
95  if( iter.isDir() && filter_match(iter.filePath(),to) )
96  {
97  directory_count++ ;
98  G::Path target = G::Path( iter.filePath() , envelope_name ) ;
99  bool copied = G::File::copy( envelope_path , target , G::File::NoThrow() ) ;
100  if( !copied )
101  failures.push_back( iter.fileName().str() ) ;
102  }
103  }
104 
105  // delete the parent envelope (ignore errors)
106  //
107  bool envelope_deleted = false ;
108  if( directory_count > 0 && failures.empty() )
109  {
110  envelope_deleted = G::File::remove( envelope_path , G::File::NoThrow() ) ;
111  }
112 
113  // notify failures
114  //
115  if( ! failures.empty() )
116  {
117  std::ostringstream ss ;
118  ss << "failed to copy envelope file " << envelope_path.str() << " into " ;
119  if( failures.size() == 1U )
120  {
121  ss << "the \"" << failures.front() << "\" sub-directory" ;
122  }
123  else
124  {
125  ss << failures.size() << " sub-directories, including \"" << failures.front() << "\"" ;
126  }
127  throw FilterError( ss.str() ) ;
128  }
129  if( directory_count == 0 ) // probably a permissioning problem
130  {
131  throw FilterError( "no sub-directories to copy into: check permissions" ) ;
132  }
133 
134  return envelope_deleted ;
135 }
136 
137 int filter_main( int argc , char * argv [] )
138 {
139  try
140  {
141  G::Arg args( argc , argv ) ;
142 
143  if( args.c() <= 1U )
144  throw FilterError( "usage error: must be run by emailrelay with the full path of a message content file" ) ;
145 
146  if( args.v(1U) == "--help" )
147  {
148  filter_help( args.prefix() ) ;
149  return 1 ;
150  }
151  else
152  {
153  return filter_run( args.v(1U) ) ? 100 : 0 ;
154  }
155  }
156  catch( std::exception & e )
157  {
158  std::cout << "<<" << e.what() << ">>" << std::endl ;
159  }
160  catch(...)
161  {
162  std::cout << "<<" << "exception" << ">>" << std::endl ;
163  }
164  return 1 ;
165 }
166 
std::string str() const
Returns the path string.
Definition: gpath.cpp:135
static std::string copyright()
Returns the copyright text.
Definition: legal.cpp:26
static bool copy(const Path &from, const Path &to, const NoThrow &)
Copies a file. Returns false on error.
Definition: gfile.cpp:70
std::string prefix() const
Returns the basename of v(0) without any extension.
Definition: garg.cpp:142
static std::string warranty(const std::string &prefix, const std::string &eol)
Returns the warranty text.
Definition: legal.cpp:31
std::string basename() const
Returns the path, excluding drive/directory parts.
Definition: gpath.cpp:162
void filter_help(const std::string &prefix)
Definition: filter.cpp:40
Path filePath() const
Returns the path of the current item.
int filter_main(int argc, char *argv[])
Definition: filter.cpp:137
bool filter_run(const std::string &content)
Definition: filter.cpp:54
bool filter_match(G::Path, std::string)
Definition: filter_copy.cpp:30
An encapsulation of a file system directory which allows for iterating through the set of contained f...
Definition: gdirectory.h:46
std::string filter_read_to(const std::string &)
Definition: filter_copy.cpp:35
Path fileName() const
Returns the name of the current item.
std::string v(size_type i) const
Returns the i'th argument.
Definition: garg.cpp:136
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurences of sub-string 'from' with 'to'...
Definition: gstr.cpp:78
size_type c() const
Returns the number of tokens in the command line, including the program name.
Definition: garg.cpp:131
static bool exists(const Path &file)
Returns true if the file (directory, link, device etc.) exists.
Definition: gfile.cpp:130
Path dirname() const
Returns the drive/directory parts of the path.
Definition: gpath.cpp:182
static bool remove(const Path &path, const NoThrow &)
Deletes the file or directory. Returns false on error.
Definition: gfile.cpp:29
An overload discriminator class for File methods.
Definition: gfile.h:56
bool more()
Returns true if more and advances by one.
#define G_EXCEPTION(class_name, description)
define as a function rather than a type if optimising for size
Definition: gexception.h:93
bool isDir() const
Returns true if the current item is a directory.
A Directory iterator.
Definition: gdirectory.h:108
A class which holds a represention of the argc/argv command line array, and supports simple command-l...
Definition: garg.h:46
bool error() const
Returns true on error. The caller should stop the iteration.
A Path object represents a file system path.
Definition: gpath.h:44