|
- //////////////////////////////////////////////////////////////////////
- // C++Mail wrapper
- // Written by Jonathan A. Foster <jon@jfpossibiliteis.com>
- // Started April 1st, 2021
- //
- // The idea is simple: A C++ class that can be used to send an email.
- // This will work by using popen() to open "mail" and allow writing
- // the email to it in standard stream fashion. This is being developed
- // for use with C++CMS to allow emailing error reports when there is a
- // crash (500 page).
- //
- // *WARN*: Requires C++11 to work. Something in the type compatibility
- // testing is misisng in previous releases.
- //
- // NOTE: I'm making this an "include" library since I don't want to
- // get into the CMake learning curve at this time. Its problematic
- // enough just getting this wedged in.
- //
- // NOTE: I found the basic popen() C++ wrapper on-line somewhere. I
- // don't remember where or who wrote it. It has been changed slightly.
- //
- // WARN: errors are essentially ignored. In other words the return of
- // pclose() isn't tested. Nor is the original popen() verified.
- //
- // TODO: error handling :-D
- //////////////////////////////////////////////////////////////////////
- #ifndef JFP_EMAIL_WRAPPER_H
- #define JFP_EMAIL_WRAPPER_H
- #include <stdio.h>
- #include <streambuf>
- #include <ostream>
- #include <memory>
- namespace JFP {
-
-
-
- //////////////////////////////////////////////////////////////////////
- // A function to escape strings for building shell commands
- //////////////////////////////////////////////////////////////////////
-
- // transform a copy so we don't cause an unexpected alteration, hence
- // the "const".
- std::string esc(const std::string s) {
- std::string r = s;
- for(
- auto it=r.find("'");
- it!=std::string::npos;
- it=r.find("'", it+4)
- ) r.replace(it, 1, "'\\''");
- return '\''+r+'\'';
- }
-
-
-
- //////////////////////////////////////////////////////////////////////
- // A "streambuf" descendant to write to a popen(..., "w") FILE
- //////////////////////////////////////////////////////////////////////
-
- struct FILEbuf: public std::streambuf {
- enum { bufsize = 4*1024 };
- char buffer[bufsize];
- FILE* fp;
- int (*close)(FILE*);
-
- int overflow(int c) {
- if(c!=std::char_traits<char>::eof()) {
- *this->pptr() = std::char_traits<char>::to_char_type(c);
- this->pbump(1);
- }
- return this->sync()
- ? std::char_traits<char>::eof()
- : std::char_traits<char>::not_eof(c);
- }
-
- int sync() {
- std::streamsize size(this->pptr()-this->pbase());
- std::streamsize done(this->fp ? fwrite(this->pbase(), 1, size, this->fp) : 0);
- this->setp(this->pbase(), this->epptr());
- return size == done ? 0 : -1;
- }
-
- FILEbuf(FILE* _fp, int(*_close)(FILE*) = fclose): fp(_fp), close(_close) {
- this->setp(this->buffer, this->buffer+(this->fp ? bufsize-1 : 0));
- }
-
- ~FILEbuf() { this->sync(); this->fp && this->close(this->fp); }
- };
-
-
-
- //////////////////////////////////////////////////////////////////////
- // Now attach it to an ostream object, which will also perform the
- // popen() call.
- //////////////////////////////////////////////////////////////////////
-
- struct popeno: public std::ostream, private virtual FILEbuf {
- popeno(std::string const& cmd):
- FILEbuf(popen(cmd.c_str(), "w"), pclose),
- std::ios(static_cast<std::streambuf*>(this)),
- std::ostream(static_cast<std::streambuf*>(this))
- { }
-
- popeno(popeno &&old):
- FILEbuf(fp, close),
- std::ios(static_cast<std::streambuf*>(this)),
- std::ostream(static_cast<std::streambuf*>(this))
- {
- old.sync(); // flush buffer so we don't need to copy it.
- }
- };
-
-
-
- //////////////////////////////////////////////////////////////////////
- // And now for a simplistic mailer
- //
- // This wrapper is basically needed to do the string /math/ for the
- // popeno constructor since the command string has to be passed to
- // inherited constructors prior to our constructor code being run.
- //
- // TODO: refactor to provide a cleaner and email only interface.
- //////////////////////////////////////////////////////////////////////
-
- popeno eMail(const std::string &to, const std::string &subject) {
- popeno r("mail -s "+esc(subject)+" "+esc(to));
- return r;
- }
-
-
-
- //////////////////////////////////////////////////////////////////////
- // EXAMPLE
- //////////////////////////////////////////////////////////////////////
- /*
- int main(int argc, char **argv) {
- eMail("jon@jfpi.net", "Test from C++")
- << "Greetings earthling\n"
- << "\n"
- << "- ChipMaster\n";
- }*/
-
-
-
- } // JFP
- #endif
|