guncat-2.00.02/build0000755000175000017500000000765114065623622013164 0ustar frankfrank#!/usr/bin/icmake -t. #define LOGENV "GUNCAT" #include "icmconf" list g_log; string g_logPath = getenv(LOGENV)[1], g_logMark, // unique-marker for g_log entries g_cwd = chdir(""); // initial working directory, ends in / int g_echo = ON; // MODIFIED, existing variable int g_installing; // set to 1 by install. int g_lognr; // unique-marker number counter for g_log entries #include "icmake/setopt" #include "icmake/cuteoln" #include "icmake/backtick" #include "icmake/run" #include "icmake/md" #include "icmake/findall" #include "icmake/loginstall" #include "icmake/logzip" #include "icmake/logfile" #include "icmake/uninstall" #include "icmake/pathfile" #include "icmake/precompileheaders" #include "icmake/special" #include "icmake/clean" #include "icmake/manpage" #include "icmake/install" #include "icmake/gitlab" void main(int argc, list argv) { string option; string strip; int idx; for (idx = listlen(argv); idx--; ) { if (argv[idx] == "-q") { g_echo = OFF; argv -= (list)"-q"; } else if (argv[idx] == "-P") { g_gch = 0; argv -= (list)"-P"; } } echo(g_echo); option = argv[1]; if (option == "clean") clean(0); if (option == "distclean") clean(1); if (option == "install") install(argv[2], argv[3]); if (option == "uninstall") uninstall(argv[2]); if (option != "") special(); if (option == "gitlab") gitlab(); if (option == "man") manpage(); if (option == "library") { // precompileHeaders(); system("icmbuild library"); exit(0); } if (argv[2] == "strip") strip = "strip"; if (option == "program") { // precompileHeaders(); system("icmbuild program " + strip); exit(0); } if (option == "xref") { // precompileHeaders(); system("icmbuild program " + strip); run("oxref -fxs tmp/lib" LIBRARY ".a > " PROGRAM ".xref"); exit(0); } printf("Usage: build [-q -P] what\n" "Where\n" " [-q]: run quietly, do not show executed commands\n" " [-P]: do not use precompiled headers\n" "`what' is one of:\n" " clean - clean up remnants of previous " "compilations\n" " distclean - clean + fully remove tmp/\n" " library - build " PROGRAM "'s library\n" " man - build the man-page (requires " "Yodl)\n" " program [strip] - build " PROGRAM " (optionally " "strip the\n" " executable)\n" " xref [strip] - same a `program', also builds " "xref file\n" " using oxref\n" " install selection [base] - to install the software in the \n" " locations defined in the INSTALL.im file,\n" " optionally below base\n" " selection can be\n" " x, to install all components,\n" " or a combination of:\n" " b (binary program),\n" " d (documentation),\n" " m (man-pages)\n" " uninstall logfile - remove files and empty directories listed\n" " in the file 'logfile'\n" " gitlab - prepare gitlab's web-pages update\n" " (internal use only)\n" "\n" ); exit(0); } guncat-2.00.02/changelog0000644000175000017500000000667414065623622014015 0ustar frankfrankguncat (2.00.02) * Removed -q from guncat's build script -- Frank B. Brokken Sat, 26 Jun 2021 15:03:45 +0200 guncat (2.00.01) * Man-page cosmetics -- Frank B. Brokken Fri, 25 Dec 2020 10:24:46 +0100 guncat (2.00.00) * Removed options --errors-OK, --locate-keys and --gpg-no-batch * Before calling gpg the encountered PGP MESSAGE section is inspected for correctness while it's written to a temporary file. If the PGP MESSAGE section contains errors gpg is not called. * Added option --no-errors terminating guncat if a PGP MESSAGE section contains errors or if gpg returns a non-zero exit value. -- Frank B. Brokken Wed, 23 Dec 2020 21:41:17 +0100 guncat (1.02.01) * Bobcat 5.04.00's Pipe class defines a close member closing both ends of the pipe. This member is now called from GPipe's destructor. * Fixed some typos in the man-page -- Frank B. Brokken Sat, 07 Mar 2020 14:45:58 +0100 guncat (1.02.00) * New options: errors-OK, time-limit; disused options: gpg-no-batch, locate-keys * Refined the Decryptor's handlePGP / insertPGPsection implementations * The passphrase is requested at the start of the program to avoid interference with output to the std. output stream * Updated options passed to gpg to gpg version 2.1, see the description of the --passphrase-fd option in the gpg(1) manual page. * Using compilation option --std=c++2a * Updated usage and man-page -- Frank B. Brokken Sun, 11 Nov 2018 16:03:27 +0100 guncat (1.01.03) * Migrated from Github to Gitlab. * Updated the C++ standard to use to c++17. * Added header-precompilation to icmconf. * Removed comment from CLASSES -- Frank B. Brokken Thu, 21 Jun 2018 19:18:26 +0530 guncat (1.01.02) * Updated the build script to icmake 8.00.04. -- Frank B. Brokken Sat, 12 Dec 2015 15:12:24 +0100 guncat (1.01.01) * Kevin Brodsky observed that the installation scripts used 'chdir' rather than 'cd'. Fixed in this release. * Kevin Brodsky also observed that the combined size of all precompiled headers might exceed some disks capacities. The option -P was added to the ./build script to prevent the use of precompiled headers. -- Frank B. Brokken Mon, 05 Oct 2015 21:25:25 +0200 guncat (1.01.00) * Update to version 1.00.00 after being operational for over one year without issues. * Added 'build uninstall'. * Updated 'INSTALL' * Guncat depends on libbobcat >= 4.00.00 (see 'required') * Standardized the (de)installation procedures -- Frank B. Brokken Sun, 04 Oct 2015 10:32:32 +0200 guncat (0.92.00) * The GPG passphrase is now requested only once. It is only requested again if a provided passphrase was incorrect. -- Frank B. Brokken Tue, 27 May 2014 15:57:34 +0200 guncat (0.91.00) * The GPG passphrase is read from /dev/tty, and not from the std. input stream (cin) anymore -- Frank B. Brokken Sun, 04 May 2014 10:55:53 +0200 guncat (0.90.00) * Initial completion of the program and man-page. -- Frank B. Brokken Sat, 03 May 2014 11:48:43 +0200 guncat (0.00.00) * Preparing the sourceforge archive, and finalizing release 0.00.00 -- Frank B. Brokken Wed, 30 Apr 2014 15:10:18 +0200 guncat-2.00.02/CLASSES0000644000175000017500000000012114065623622013140 0ustar frankfrankglobals options gpghandler pgpsection decryptor outputbuf ooutputstream guncat guncat-2.00.02/decryptor/0000755000175000017500000000000014065623622014141 5ustar frankfrankguncat-2.00.02/decryptor/setverbose.cc0000644000175000017500000000112614065623622016631 0ustar frankfrank#include "decryptor.ih" void Decryptor::setVerbose() { string const &verbose = d_options.verbose(); if (not verbose.empty()) // if a msgname was specified: { if (verbose == "-") g_verbose = &cerr; // write to cerr else { d_fverbose = unique_ptr{ // or open a file new ofstream{ Exception::factory(verbose) } }; g_verbose = d_fverbose.get(); } } } guncat-2.00.02/decryptor/error.cc0000644000175000017500000000077714065623622015614 0ustar frankfrank#include "decryptor.ih" // static void Decryptor::error(ostream &out, int ret, pair const &range) { ostringstream msg; msg << "In " << g_filename << ':' << range.first << ':' << range.second << ": cannot decrypt PGP section, gpg returns " << ret; string msgTxt{ msg.str() }; starred(out, msgTxt); if (g_verbose) *g_verbose << msgTxt << '\n'; if (Options::instance().noErrors()) throw Exception{} << msgTxt; } guncat-2.00.02/decryptor/handlepgp.cc0000644000175000017500000000166114065623622016416 0ustar frankfrank//#define XERR #include "decryptor.ih" void Decryptor::handlePGP(istream &in, ostream &out) { PGPSection pgpSection{ in }; // obtain the PGP MESSAGE if (g_verbose) *g_verbose << fileInfo() << ": PGP HEADER" << endl; // got a complete if (pgpSection.verify(out)) // PGP section { // decrypt it unless only if (not d_options.pgpRanges()) // ranges are requested { if (int ret = d_gpgHandler.process(pgpSection.str()); ret != 0) error(out, ret, pgpSection.range()); } return; } // unless suppressed: if (not d_options.skipIncomplete()) // show the INcomplete out << pgpSection.str().rdbuf(); // PGP MESSAGE } guncat-2.00.02/decryptor/decryptor.ih0000644000175000017500000000043614065623622016501 0ustar frankfrank#include "decryptor.h" #include "../xerr/xerr.ih" #include #include #include "../globals/globals.h" #include "../options/options.h" #include "../pgpsection/pgpsection.h" #include "../gpghandler/gpghandler.h" using namespace std; using namespace FBB; guncat-2.00.02/decryptor/decryptor.h0000644000175000017500000000140214065623622016322 0ustar frankfrank#ifndef INCLUDED_DECRYPTOR_ #define INCLUDED_DECRYPTOR_ #include #include #include class Options; class GPGHandler; class Decryptor { Options const &d_options; GPGHandler &d_gpgHandler; std::unique_ptr d_fverbose; public: Decryptor(GPGHandler &gpgHandler); // -----BEGIN PGP MESSAGE----- // was just read by void handlePGP(std::istream &in, // Guncat::process std::ostream &out); private: void setVerbose(); static void error(std::ostream &out, int ret, std::pair const &range); }; #endif guncat-2.00.02/decryptor/icmconf0000644000175000017500000000010014065623622015471 0ustar frankfrank#define LIBRARY "decryptor" #include "../icmconf.lib" guncat-2.00.02/decryptor/decryptor1.cc0000644000175000017500000000024314065623622016543 0ustar frankfrank#include "decryptor.ih" Decryptor::Decryptor(GPGHandler &gpgHandler) : d_options(Options::instance()), d_gpgHandler(gpgHandler) { setVerbose(); } guncat-2.00.02/decryptor/driver/0000755000175000017500000000000014065623622015434 5ustar frankfrankguncat-2.00.02/decryptor/driver/icmconf0000644000175000017500000000103314065623622016772 0ustar frankfrank#define CLS #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "guncat bobcat" #define ADD_LIBRARY_PATHS "../../../tmp" #define DEFCOM "program" guncat-2.00.02/decryptor/driver/main.cc0000644000175000017500000000232714065623622016673 0ustar frankfrank//#define XERR #include "main.ih" namespace { string terminating{ "Terminating" }; } int main(int argc, char **argv) try { if (argc == 1) { cerr << "file containing PGP SECTION required. If a second arg\n" "is provided the passphrase entered at -p is shown\n"; return 1; } Arg const &arg = prepareArgs(argc, argv); (terminating += ' ') += arg.basename(); Options const &options = Options::instance(); ifstream in(arg[0]); Decryptor decryptor; if (options.getPassphrase()) { string pass; OneKey key; cout << "? "; while (true) { int ch = key.get(); if (ch == '\n') break; pass += ch; } if (arg.nArgs() > 1) cout << '`' << pass << "'\n"; decryptor.setPassphrase(pass); } in.ignore(100, '\n'); // skip BEGIN PGP MESSAGE decryptor.handlePGP(in); } catch (int x) { cerr << "returning " << x << '\n'; return 0; } catch (exception const &exc) { cerr << terminating << ": " << exc.what() << '\n'; return 1; } catch (...) { cerr << "Unexpected exception\n"; return 1; } guncat-2.00.02/decryptor/driver/main.ih0000644000175000017500000000044114065623622016701 0ustar frankfrank#include "../../xerr/xerr.ih" #include #include #include #include #include #include "../../options/options.h" #include "../decryptor.h" using namespace std; using namespace FBB; Arg const &prepareArgs(int argc, char **argv); guncat-2.00.02/decryptor/driver/pgpmsg0000644000175000017500000000730714065623622016663 0ustar frankfrank-----BEGIN PGP MESSAGE----- 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 v2TFMhUcbg6TeA== =HbFf -----END PGP MESSAGE----- guncat-2.00.02/documentation/0000755000175000017500000000000014065623622014777 5ustar frankfrankguncat-2.00.02/documentation/man/0000755000175000017500000000000014065623622015552 5ustar frankfrankguncat-2.00.02/documentation/man/guncat.yo0000644000175000017500000001772714065623622017422 0ustar frankfrankgagmacrowarning(server FILE) includefile(../../release.yo) htmlbodyopt(text)(#27408B) htmlbodyopt(bgcolor)(#FFFAF0) gagmacrowarning(guncat) mailto(f.b.brokken@rug.nl) DEFINEMACRO(lsoption)(3)(\ bf(--ARG1)=tt(ARG3) (bf(-ARG2))\ ) DEFINEMACRO(laoption)(2)(\ bf(--ARG1)=tt(ARG2)\ ) DEFINEMACRO(loption)(1)(\ bf(--ARG1)\ ) DEFINEMACRO(soption)(1)(\ bf(-ARG1)\ ) DEFINEMACRO(u)(0)(bf(guncat)) DEFINEMACRO(U)(0)(bf(Guncat)) DEFINEMACRO(g)(0)(bf(gpg)) manpage(guncat)(1)(_CurYrs_)(guncat__CurVers_) (guncat - unencrypting file concatenation) manpagename(guncat)(catenates files, unencrypting pgp encrypted sections) manpagesynopsis() bf(guncat) [OPTIONS] tt([file(s)]) nl() [OPTIONS] - cf. section bf(OPTIONS)nl() [file+nop()(s)] - optional files to process (cf. section bf(INPUT FILE(S)))nl() manpagedescription() U() was designed to tackle a problem encountered with (partially) PGP encrypted files (which may exist in, e.g., mailboxes). Tools to process text-files (like bf(grep)(1), or bf(less)(1)) may be used to process those files, but those tools leave PGP encrypted sections inside such files as-is. As a consequence, browsing the `real' contents (i.e., clear-text sections and the unencrypted content of PGP encrypted sections) of those files is difficult. U() acts comparably to bf(cat), but unencrypts encrypted sections encountered in the files processed by u(), copying the unencrypted information to u()'s standard output stream, which may thereupon be processed by other tools. PGP/GPG encrypted sections are surrounded by the following markers: verb( -----BEGIN PGP MESSAGE----- ) and verb( -----END PGP MESSAGE----- ) When u() encounters such sections they are processed by g()(1). bf(Gpg) needs a passphrase to unencrypt such sections. If not already available (from bf(gpg-agent)(1)) the required passphrase is requested by u(), whereafter it is used by g(). When an incorrect passphrase is entered two additional attempts to provide the correct passphrase are allowed. If the third attempt also fails, u() terminates. Files processed by u() may have to be repositioned. If repositioning is not supported u() terminated with an error message. manpagesection(RETURN VALUE) U() returns 0 to the operating system unless an error occurs (0 is also returned when the option em(--gpg-command) is specified). 1 is returned if g() could not decrypt an encrypted section or if u() is started without arguments or options manpagesection(INPUT FILE(S)) When no file arguments are provided input may be provided using standard input stream redirection. When option em(--passphrase) is specified the first line of the first file that is processed is read as the passphrase to be used. This line is ignored if bf(gpg-agent) already can provide the correct passphrase. Otherwise, when a thus specified passphrase is incorrect, u() terminates. Any other argument is considered a filename (path specifications are allowed) specifying a file to be processed (in sequence) by u(). If a file cannot be read u() terminates with an error message. manpageoptions() In the following overview of options single letter options, when available, are listed between parentheses following their associated long-option alternatives. Single letter options require arguments if their long option alternatives require arguments as well. itemization( it() loption(gpg-command)nl() Show the gpg command that would be used, and quit, returning 0. it() lsoption(gpg-option)(m)(option)nl() Add em(option) to g()'s call. If the option contains blanks, surround em(option) by single or double quotes. Option em(gpg-option) may repeatedly be specified. it() laoption(gpg-path)(path)nl() Path to the g() program (default: em(/usr/bin/gpg)) it() loption(help) (soption(h))nl() Basic usage information is written to the standard output stream. it() lsoption(less)(l)(path)nl() output is written to '/usr/bin/less'. By default output is written to the std. output stream. This option cannot be specified when either option em(--pipe) or option em(--write) is specified. it() loption(no-errors)nl() When this options is specified u() terminates g() returns a non-zero exit value. it() loption(passphrase) soption(p)nl() By default the passphrase is read by u() after prompting the user to enter the passphrase. The passphrase is not echoed. If input redirection is used or if input files are specified option em(--passphrase) can be specified to read the passphrase from the first line of the first input stream that is read by u(). In that case the input stream's first line is (of course) not written to the output stream. When the em(--passphrase) option is specified and the provided password is incorrect, u() terminates. it() lsoption(pipe)(P)(path)nl() Full path to a program receiving guncat's output. By default output is written to the std. output stream. This option cannot be specified when either option em(--less) or option em(--write) is specified. it() loption(pgp-ranges) soption(r)nl() the lines-ranges of complete em(PGP MESSAGE) sections are reported. No additional output is produced. it() loption(quoted-printable) soption(q)nl() merely decrypt PGP messages, keeping their quoted-printable content (by default quoted-printable content like 'em(=3D)' is converted to ascii). it() loption(reduce-headers) soption(R)nl() When encountering mail headers (starting at lines beginning with `em(From )' and ending at the next empty line) only output the mail headers em(Cc:, Date:, From:, Subject:), and em(To:). it() loption(section-lines) soption(S)nl() In the output precede decrypted em(PGP MESSAGE) sections by their line numbers, using a format like verb( **************************** filename:43:104: PGP MESSAGE **************************** ) where the first number refers to the first line number of the PGP section and the second number refers to last line number of the PGP section it() loption(skip-incomplete) soption(s)nl() Incomple em(PGP MESSAGE) sections are ignored and are not outputted. By default the program's output also contain the lines of any incomplete em(PGP MESSAGE) sections that were encountered. it() lsoption(time-limit)(T)(seconds)nl() Option em(--time-limit) is used to specify the max. time in seconds that g() is allowed to run while decrypting a single encrypted section. By default no time limit is used. This option is useful when the file to process might contain errors in encrypted sections (like a missing em(END PGP MESSAGE) line). it() loption(tty-OK) soption(t)nl() Option em(--no-tty) is not specified when calling g(). By default it is specified. it() lsoption(verbose)(V)(path)nl() Path to where u() should write additional messages. Specify - to write the messages to the standard error stream. it() loption(version) (soption(v))nl() U()'s version number is written to the standard output stream, terminating u(), returning exit value 0. it() lsoption(write)(W)(path)nl() output is written to em(path). If em(path) already exists g() terminates. By default output is written to the std. output stream. This option cannot be specified when either option em(--less) or option em(--pipe) is specified. ) manpageseealso() bf(gpg)(1), bf(gpg-agent)(1), bf(grep)(1), bf(less)(1). manpagebugs() None reported manpagesection(COPYRIGHT) This is free software, distributed under the terms of the `GNU General Public License'. Copyright remains with the author. U() is available at em(https://fbb-git.gitlab.io/guncat/) manpageauthor() Frank B. Brokken (f.b.brokken@rug.nl). guncat-2.00.02/globals/0000755000175000017500000000000014065623622013551 5ustar frankfrankguncat-2.00.02/globals/data.cc0000644000175000017500000000032414065623622014770 0ustar frankfrank#include "globals.ih" size_t g_lineNr; string g_filename; string g_beginPGP{ "-----BEGIN PGP MESSAGE-----" }; string g_endPGP{ "-----END PGP MESSAGE-----" }; ostream *g_verbose = 0; // no messages if 0 guncat-2.00.02/globals/nextline.cc0000644000175000017500000000020714065623622015705 0ustar frankfrank#include "globals.ih" istream &nextline(istream &in, string &line) { if (getline(in, line)) ++g_lineNr; return in; } guncat-2.00.02/globals/globals.ih0000644000175000017500000000022314065623622015513 0ustar frankfrank#include "globals.h" #include "../xerr/xerr.ih" #include #include #include #include using namespace std; guncat-2.00.02/globals/icmconf0000644000175000017500000000007614065623622015115 0ustar frankfrank#define LIBRARY "globals" #include "../icmconf.lib" guncat-2.00.02/globals/starred.cc0000644000175000017500000000042614065623622015526 0ustar frankfrank#include "globals.ih" void starred(std::ostream &out, std::string const &msg) { out << '\n' << setfill('*') << setw(msg.length()) << '*' << '\n' << msg << '\n' << setw(msg.length()) << '*' << '\n' << setfill(' ') << '\n'; } guncat-2.00.02/globals/fileinfo.cc0000644000175000017500000000020314065623622015646 0ustar frankfrank#include "globals.ih" #include string fileInfo() { return "In " + g_filename + ", line " + to_string(g_lineNr); } guncat-2.00.02/globals/globals.h0000644000175000017500000000057114065623622015350 0ustar frankfrank#ifndef INCLUDED_GLOBALS_H_ #define INCLUDED_GLOBALS_H_ #include extern size_t g_lineNr; extern std::string g_filename; extern std::string g_beginPGP; extern std::string g_endPGP; extern std::ostream *g_verbose; std::string fileInfo(); std::istream &nextline(std::istream &in, std::string &line); void starred(std::ostream &out, std::string const &msg); #endif guncat-2.00.02/gpghandler/0000755000175000017500000000000014065623622014241 5ustar frankfrankguncat-2.00.02/gpghandler/parentprocess.cc0000644000175000017500000000140014065623622017433 0ustar frankfrank#define XERR #include "gpghandler.ih" void GPGHandler::parentProcess() { IFdStream fromChild(d_childOutput.readOnly(), 1000); IFdStream childMessages(d_childMessages.readOnly(), 500); { OFdStream toChild(d_childInput.writeOnly(), 1000); if (d_checkPassphrase) toChild << "sign\n"; else toChild << d_in->rdbuf(); } d_ret = waitForChild(); if (d_ret != 0) return; if (d_checkPassphrase) d_checkPassphrase = false; else if (d_options.quotedPrintable()) // accept quoted print. output d_out << fromChild.rdbuf(); else { IQuotedPrintableBuf decode{ fromChild }; istream din(&decode); d_out << din.rdbuf(); } } guncat-2.00.02/gpghandler/getpassphrase.cc0000644000175000017500000000106114065623622017417 0ustar frankfrank//#define XERR #include "gpghandler.ih" bool GPGHandler::getPassphrase() { if (not d_passphrase.empty()) // a passphrase is already available return true; cerr << "Enter passphrase (empty line to skip): "; struct termios ttySaved; int fd = echo(&ttySaved); // switch off echoing, fd to /dev/tty IFdStream in(fd); // get the passphrase from /dev/tty getline(in, d_passphrase); echo(&ttySaved, true); // restore the echoing state cerr << '\n'; return not d_passphrase.empty(); } guncat-2.00.02/gpghandler/data.cc0000644000175000017500000000011614065623622015457 0ustar frankfrank//#define XERR #include "gpghandler.ih" unsigned GPGHandler::s_nRetries = 0; guncat-2.00.02/gpghandler/gpghandler.ih0000644000175000017500000000101114065623622016667 0ustar frankfrank#include "gpghandler.h" #include "../xerr/xerr.ih" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../globals/globals.h" #include "../options/options.h" using namespace std; using namespace FBB; guncat-2.00.02/gpghandler/gpghandler.h0000644000175000017500000000263714065623622016535 0ustar frankfrank#ifndef INCLUDED_GPGHANDLER_ #define INCLUDED_GPGHANDLER_ #include #include #include class Options; class GPGHandler: public FBB::Fork { std::ostream &d_out; Options const &d_options; std::istream *d_in; bool d_checkPassphrase; bool d_passphraseFirstLine; std::string d_gpgCommand; std::string d_passphrase; FBB::Pipe d_childInput; FBB::Pipe d_childOutput; FBB::Pipe d_childMessages; int d_ret; // return value of the gpg call static unsigned s_nRetries; // # times a pwd was requested public: // passphrase may have been // provided via the 1st input line GPGHandler(std::ostream &out, bool passphraseFirstLine); ~GPGHandler() override; // closes the pipes void checkPassphrase(std::istream &in); int process(std::istream &in); private: std::string passphraseFd(FBB::Pipe &pipe) const; bool getPassphrase(); // get the passphrase from /dev/tty void retryPassphrase(); void resetPipes(); void childRedirections() override; void childProcess() override; void parentProcess() override; static int echo(struct termios *ttySaved, bool reset = false); }; // #endif guncat-2.00.02/gpghandler/passphrasefd.cc0000644000175000017500000000131414065623622017232 0ustar frankfrank#include "gpghandler.ih" string GPGHandler::passphraseFd(Pipe &pipe) const { // specify the fd receiving the // passphrase string ret{ " --pinentry-mode loopback" " --passphrase-fd " + to_string(pipe.readFd()) }; OFdStream pwd(pipe.writeFd()); // create an ostream for it // write the passphrase, which // will be read by gpg from the pwd << d_passphrase << endl; // pipe return ret; // return gpg's options } guncat-2.00.02/gpghandler/retrypassphrase.cc0000644000175000017500000000073514065623622020014 0ustar frankfrank#include "gpghandler.ih" void GPGHandler::retryPassphrase() { if (d_passphraseFirstLine) throw Exception{} << "Incorrect passphrase on 1st line of input"; switch (++s_nRetries) { case 1: break; case 4: throw Exception{} << "Quitting after three passphrase attempts\n"; default: cerr << "Incorrect passphrase. Try again...\n"; break; } d_passphrase.clear(); getPassphrase(); } guncat-2.00.02/gpghandler/childprocess.cc0000644000175000017500000000051014065623622017226 0ustar frankfrank#define XERR #include "gpghandler.ih" void GPGHandler::childProcess() { Pipe pipe; Process gpg{ Process::DIRECT, Process::NO_PATH, d_gpgCommand + passphraseFd(pipe) }; gpg.setTimeLimit(d_options.timeLimit()); // 0 -> no time limit gpg.start(); } guncat-2.00.02/gpghandler/resetpipes.cc0000644000175000017500000000036414065623622016736 0ustar frankfrank//#define XERR #include "gpghandler.ih" void GPGHandler::resetPipes() { d_childInput.close(); d_childInput = Pipe{}; d_childOutput.close(); d_childOutput = Pipe{}; d_childMessages.close(); d_childMessages = Pipe{}; } guncat-2.00.02/gpghandler/icmconf0000644000175000017500000000010114065623622015572 0ustar frankfrank#define LIBRARY "gpghandler" #include "../icmconf.lib" guncat-2.00.02/gpghandler/echo.cc0000644000175000017500000000055414065623622015472 0ustar frankfrank#include "gpghandler.ih" // static int GPGHandler::echo(struct termios *ttySaved, bool reset) { int fd = open("/dev/tty", O_RDONLY); struct termios tty; tcgetattr(fd, &tty); if (reset) tty = *ttySaved; else { *ttySaved = tty; tty.c_lflag &= ~ECHO; } tcsetattr(fd, TCSANOW, &tty); return fd; } guncat-2.00.02/gpghandler/childredirections.cc0000644000175000017500000000034414065623622020247 0ustar frankfrank//#define XERR #include "gpghandler.ih" void GPGHandler::childRedirections() { d_childInput.readFrom(Redirector::STDIN); d_childOutput.writtenBy(Redirector::STDOUT); d_childMessages.writtenBy(Redirector::STDERR); } guncat-2.00.02/gpghandler/process.cc0000644000175000017500000000030314065623622016222 0ustar frankfrank#define XERR #include "gpghandler.ih" int GPGHandler::process(istream &in) { d_in = ∈ resetPipes(); fork(); return d_ret; // this section is now completed } guncat-2.00.02/gpghandler/destructor.cc0000644000175000017500000000017414065623622016750 0ustar frankfrank//#define XERR #include "gpghandler.ih" GPGHandler::~GPGHandler() { d_childInput.close(); d_childOutput.close(); } guncat-2.00.02/gpghandler/gpghandler1.cc0000644000175000017500000000055414065623622016750 0ustar frankfrank//#define XERR #include "gpghandler.ih" GPGHandler::GPGHandler(ostream &out, bool passphraseFirstLine) : d_out(out), d_options(Options::instance()), d_in(0), d_checkPassphrase(true), d_passphraseFirstLine(passphraseFirstLine), d_gpgCommand(d_options.gpgPath() + d_options.gpgSign()) { xerr("Initial GPG command: " << d_gpgCommand); } guncat-2.00.02/gpghandler/checkpassphrase.cc0000644000175000017500000000142414065623622017720 0ustar frankfrank//#define XERR #include "gpghandler.ih" void GPGHandler::checkPassphrase(istream &in) { if (d_options.pgpRanges()) // no passphrase needed when merely return; // reporting ranges if (d_passphraseFirstLine) getline(in, d_passphrase); while (true) { fork(); switch (d_ret) { case 2: retryPassphrase(); resetPipes(); break; default: // some error... throw Exception{} << "gpg returned " << d_ret; case 0: // no errors d_gpgCommand = d_options.gpgPath() + d_options.gpgDecrypt(); return; // this section is now completed } } } guncat-2.00.02/gpghandler/driver/0000755000175000017500000000000014065623622015534 5ustar frankfrankguncat-2.00.02/gpghandler/driver/icmconf0000644000175000017500000000103314065623622017072 0ustar frankfrank#define CLS #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "guncat bobcat" #define ADD_LIBRARY_PATHS "../../../tmp" #define DEFCOM "program" guncat-2.00.02/gpghandler/driver/main.cc0000644000175000017500000000152214065623622016767 0ustar frankfrank#include "main.ih" namespace { string terminating{ "Terminating" }; } int main(int argc, char **argv) try { // if (argc == 1) // { // cerr << "file containing PGP SECTION required\n"; // return 1; // } Arg const &arg = prepareArgs(argc, argv); (terminating += ' ') += arg.basename(); Options const &options = Options::instance(); ifstream in(arg[0]); // string passwd; // if (options.getPassphrase()) // getline(in, passwd); GPGHandler handler(options.passphraseFirstLine()); handler.checkPassphrase(cin); // handler.process(in); } catch (int x) { cerr << "returning " << x << '\n'; return 0; } catch (exception const &exc) { cerr << terminating << ": " << exc.what() << '\n'; return 1; } catch (...) { cerr << "Unexpected exception\n"; return 1; } guncat-2.00.02/gpghandler/driver/main.ih0000644000175000017500000000035214065623622017002 0ustar frankfrank#include #include #include #include #include "../../options/options.h" #include "../gpghandler.h" using namespace std; using namespace FBB; Arg const &prepareArgs(int argc, char **argv); guncat-2.00.02/gpghandler/driver/pgpmsg0000644000175000017500000000730714065623622016763 0ustar frankfrank-----BEGIN PGP MESSAGE----- hQIMA7nVTanLuqxkAQ//a6nu144MgtS1RnUsJBLQXPjTdJo9mR0b58grSMEc1IMB bMfvYkR6L7Vt9h0Ctx63spsZUmEmgsNsnTEFK3rVUGIUynUSh6+ZOp2sYpzvxIPA EEfYFPLRyFdHRLk4S/E4tCUqkljBzGFJtYv67/zr6yiqj7ffO3KwxWGDxnQb5VMC UU/FjYisoDbZCq0nXmYHx5RgQ5duscx9+yJdaxtcOFSVCKwhaXqU0EjHZ5MMWgt/ RMpuRbR37yCvx/rZ9/PFIkguq7jPIw3LifrOPCR/ydiOWAjidsqT01ahIXzeTRzj ssTd6PG3sAjPPcSpoNbU4bBW5Ws8gl8ZNt4GOaGvO+QTTJFpPI+pHqyCdG7EFFeB OdmrBaVoZ5ZixFFVELIJwih86AK3JK1e38xfRa3jn1MxrXHkBadu2mVWXWie0E24 jRZfJocP7qcntIDQBWJicr8jrSMGv+H1Apr09hqeSYrD5rUomZplk8xAHURfMFYx GfVjiobrXBXjp6rZNLGdKSgGgjWiTLCFpfYTEnqHIrJAs2mbEkVh+/nvNroTxjfW XJ8ABMyRnAPw8P78FJR5i0bu9VjXRlNNOkR1caU6JG4y4MhSqUn8FHtu7ct0j6Eb BicW4RNCzPZ36OAy+EnUFt6hqkyVbSOTaqGTC4d/HM1+3gdw5MmhYRVqejwIvPKF AgwDLs4+5r2eXcUBD/0bZNrYWSnj37ly/MQ4BwAJF6utrYLzeszsN9vmS+DmFqQX hqNfOpT0WyPqnPig48wrz2PU+MwrMLnXAqFvp5fJpyXsUQP1VabHjkQ/eIo/ALzp 87KDF6Z/vk5lB9KnxynEG+HW7QS/GEdImw9C4xDstu4AE5wVDGdWwwK0TP9ldsDn Y6GSYWsa4BA+QS1rw1aR97JfOQbQ4HO8y3mPi/mqkqfV9MYunDZONPaHA9BsDhME AjMSr4p0nfSlU4UezUMdF0T+6/MuynFUuVVDF3TOw5YSxky2usM8aumi6YZmZ9+E sjdmgN/adTWFzLs4D0bufKQpRE67dqT1A/ZqANy4Vre+CZn3thhEBO+wSanAbh3o 2QW1466a2KUOWv6rtoKEKGqjo3w9uqlbCIDvBMkI8cW+3+2SPalGs8pomrZgc1J2 /bZJsuAbRoFWZwtoJD9+PoVyXCM4eBTKXULKqqRZcGZBPrtHg96CTB0YlESjAT1Q 3myf1VI2A8i+gjpGgR8zohmbSab8MtpLJV0rVBLWLdDc9Pxv+6rXS5YTOklHvm/D rreJU8nSo/0/jehpEfeEb5vADwWo95LyBwrICsgGP1oZz31gpYXQWOUy+rsiVu97 GA6ewH2SQv8OT1nU6xZNl7Qtie5arPRCbTQMrUx1QUd96/tLiVuYTBrRDwTCvoUB DAPGX8kyb0KYWwEH/RjTAp+Wh+oRTAZ5LicA+zLB2P629A2h8Ajntc/B+G03u42y Iau9Q2kIh8lo6vl4MD1xjRgwQ5qy7dpP8rd1r+kogRNx765BI8fjM5OXxuM58AW5 1/BiXtNU4BMKE2gupKA6lBFBA4gWgamyV9Q9II1bl+Wz3DwK/+/5rHgfhfG1drx+ qd554gMkw8SHxdnZB6YnIauuvYGDGrGvIsGmgLPWNLH+9XFJuUDdIF1UYD16+1SE 4C+m2Ulr6NuvNkBCrWG3PZXQyGl7zUC5tChTWGir8QXH2Dep4xxAqhFPd1g5Vfz0 uNFWx1GdSxciW7oXCMhb40kAKJ1pGRNOMDTNk9fS6gHmvuLQsnSoMl18GtAgq4t0 N4nZRsJksvfRkeLhj459yxCrkSuiQ5OYz5kbhhrILenxDSP/akDbxpcVNPvLcVUB TU0LHewSSRURFvxmm4QuKF4GltOw9sJEEv84XCyCCI7QwqNjjg5BQxO2GcuGkriX sOoeaNFoBBkXZP/xQ3c/O0Gzt7pdvmSHV3oiSShuEgOiQXXHARhyPLr1Pd3eFmUD CBz3FZpjWEGu53+1Ii4dH3UpvsSba7LCJjoVngs/YbL0xdGgS+ihRUvzKs8i9Ac1 /FKna+VYYbpSKfqZBZnUSoJb5NMg8cWdwFMQbrgexpo8FtxKaFFpDlH3ZuH13oTZ Jkij4JJUW/tz9N3pRS3ydN1BP6G8E30Q1m4pkgvFJfFwytY8sF+0h8mWDllL8XZu AyvlSRlz5y1RMmoCJSQzMVdSZdVBhoamjFfUi/hCbvH/xYCEr3g+1M8B19fNlIr7 zV2d4X7rNnABNRpXqm6yi1kKDoUuZVDvX/mkQkMecksf22H59UDbpN7RvMeWELsf 0Z6suxnMjP3Ors91w2kf6FvSEdvLga8PdD+xqkzLHgui8x32OWdsESX+F+udwYrE Ci8QSnNtliE57Qfzp1ef58lVvqqLV5iofLlCnjq5BGeB60wwsxqEodcCy0yWjtL5 I/IYmUxWPoMSgsKiOVt4bWmO8vwD3CAW2yRv1+y0UN97FvdfQjmPdX9i/iocj4ku hpe7sDMSREJvMNEdPJ6b/869lrDAat0Y29aqHbDeuwp/O9kXni1MyFHBEKW4vQQ5 1KyyCvrkAvlcORKGGWNy4Uthih/AKJ3AFsoEo7tqZQKXIQ71Mk4OAetDoEGbZjQ2 T3SbVUdYOz+z2b3iPhe/UEKT3YPqRbyjDn8j8bdvlqJwchM8wLxlEYsY+FllsqQ5 FbeV6WIg4QmG2Aj6je1bMazHRL9rMHvd/Tp6QyoUuWY+k0PbG05YQNvNm5nx9IEq Fubad7QpAR7Ogeb6jmuT9/9tqO8pUsV8XWgQY1B3GSjXlqZwyAJbZwEaoKdNoWJn BZwXjLFYXtH7iif5yGZNHSQX64zHF23pn2/G/g/Y7jKyiLbj5MyN0P/5ev3GVSJK y9J8Veo3gaOoZGOLXIv7cafi9/fCLwBk2SiF7fNJEWRnL9PeAavd0t9pLBm+Eeq4 jW8tonJhHe73JiK3WIu8kZqw3oxcm1jkVOQmWDPXbbHdLfW7rEAdjHCV8jhA+EPz PE2BUUYW4Z/3inUut/0R5YmdpUxSeNo3ju3Pt/5eP5YPekw09erTfJSfwnFTkL3Y KCoJ3hKh1Y676xexD9y+N4lXGZDU0NOaEYQexUB0PtRcJESpILHY4VkJqq+lPHHA yaUcHPKkbmqQYUcNlv2Do/oph8aaYFvhYW68AWOgVxxYIl4bQtgsI3sAfHsHPhT/ zsIAze05Z9tGPEN1BN/30TUyAXSLApQE/AUZQE4zP0nbaW7ApYZAdY89F2j3ABeX MRZev7cUdLNbhbEFkf3pTyU4qxM52UsoydPQV3ZOVk+ANSfJwCEXAQTYtXXNgfkD ZsMRDSCv9SufQOBsDUyq8uLUoo186TQlsUEUiKvJVAq3wg/AIORhsbL6V+V9MFuu ETgXGvdxq/SZzgx7BDJOZ00odcdkXuDa57fGM8YDd+6PMINUkfufnmlgrY1GaD6y c3ZdCRuEPQYtpzkX4hSjD4GAxd83gwlTsEBjZQUCJUslnwFtsAOtggS+Isvx7gHW M2g+Jp2Q2plPFzzu3WiZBkkftzgmJZ2d8usZpB6S5MM6jiV1qYC2ZKSX/w2ZvX3R SxauzCqoMpPMRXTt+RFE9p56mL7yyrMoo6FY49plwYKb0Bky3IwIP0Ec2sjAD4aM v2TFMhUcbg6TeA== =HbFf -----END PGP MESSAGE----- guncat-2.00.02/guncat/0000755000175000017500000000000014065623622013407 5ustar frankfrankguncat-2.00.02/guncat/processcin.cc0000644000175000017500000000014514065623622016066 0ustar frankfrank#include "guncat.ih" void Guncat::processCin() { g_filename = "stdin"; process(cin); } guncat-2.00.02/guncat/data.cc0000644000175000017500000000032514065623622014627 0ustar frankfrank#include "guncat.ih" char const *const Guncat::s_accept[] = { "Cc: ", "Date: ", "From: ", "Subject: ", "To: " }; char const *const *const Guncat::s_acceptEnd = s_accept + size(s_accept); guncat-2.00.02/guncat/guncat.ih0000644000175000017500000000044614065623622015216 0ustar frankfrank#include "guncat.h" #include "../xerr/xerr.ih" #include #include #include #include #include "../globals/globals.h" #include "../options/options.h" #include "../ooutputstream/ooutputstream.h" using namespace std; using namespace FBB; guncat-2.00.02/guncat/run.cc0000644000175000017500000000020214065623622014514 0ustar frankfrank#include "guncat.ih" void Guncat::run() { if (d_gpgCommand) showGPGcommand(); else programArguments(); } guncat-2.00.02/guncat/guncat.h0000644000175000017500000000176314065623622015050 0ustar frankfrank#ifndef INCLUDED_GUNCAT_ #define INCLUDED_GUNCAT_ #include #include #include #include #include "../decryptor/decryptor.h" #include "../gpghandler/gpghandler.h" class Options; class Guncat { Options const &d_options; std::unique_ptr d_ofstream; std::ostream &d_out; bool d_gpgCommand; bool d_pgpRanges; bool d_passphraseFirstLine; // handled in process() bool d_reduceHeaders; GPGHandler d_gpgHandler; Decryptor d_decryptor; static char const *const s_accept[]; static char const *const *const s_acceptEnd; public: Guncat(); void run(); private: void showGPGcommand() const; bool onlyCin(); void processCin(); void process(std::istream &in); void programArguments(); bool reduceHeaders(std::string const &line); static std::ostream *outputStream(Options const &options); }; #endif guncat-2.00.02/guncat/reduceheaders.cc0000644000175000017500000000066314065623622016526 0ustar frankfrank#define XERR #include "guncat.ih" bool Guncat::reduceHeaders(string const &line) { if (line.find_first_not_of(" \t") == string::npos) // no non-blank chars return false; if ( find_if(s_accept, s_acceptEnd, [&](char const *target) { return line.find(target) == 0; } ) != s_acceptEnd ) d_out << line << '\n'; return true; } guncat-2.00.02/guncat/icmconf0000644000175000017500000000007514065623622014752 0ustar frankfrank#define LIBRARY "guncat" #include "../icmconf.lib" guncat-2.00.02/guncat/outputstream.cc0000644000175000017500000000053614065623622016476 0ustar frankfrank#include "guncat.ih" // static ostream *Guncat::outputStream(Options const &options) { string path{ options.pipePath() }; if (not path.empty()) return new OOutputStream{ path }; path = options.writePath(); return path.empty() ? 0 : new ofstream{ Exception::factory(path) }; } guncat-2.00.02/guncat/programarguments.cc0000644000175000017500000000072614065623622017320 0ustar frankfrank#include "guncat.ih" void Guncat::programArguments() { if (onlyCin()) return; Arg &arg = Arg::instance(); for (size_t idx = 0, end = arg.nArgs(); idx != end; ++idx) { g_filename = arg[idx]; ifstream in{ Exception::factory(g_filename) }; if (idx == 0) // set passphrase before d_gpgHandler.checkPassphrase(in); // processing the 1st files process(in); } } guncat-2.00.02/guncat/process.cc0000644000175000017500000000110714065623622015373 0ustar frankfrank#define XERR #include "guncat.ih" void Guncat::process(istream &in) { string line; g_lineNr = 0; bool reduce = false; while (nextline(in, line)) { if (line == g_beginPGP) { d_decryptor.handlePGP(in, d_out); continue; } if (d_pgpRanges) continue; if (not reduce and d_reduceHeaders and line.find("From ") == 0) reduce = true; if (reduce) reduce = reduceHeaders(line); else d_out << line << '\n'; } d_out.flush(); } guncat-2.00.02/guncat/guncat1.cc0000644000175000017500000000063514065623622015264 0ustar frankfrank#define XERR #include "guncat.ih" Guncat::Guncat() : d_options(Options::instance()), d_ofstream(outputStream(d_options)), d_out(d_options.stdOut() ? cout : *d_ofstream.get()), d_gpgCommand(d_options.gpgCommand()), d_pgpRanges(d_options.pgpRanges()), d_reduceHeaders(d_options.reduceHeaders()), d_gpgHandler(d_out, d_options.passphraseFirstLine()), d_decryptor(d_gpgHandler) {} guncat-2.00.02/guncat/showgpgcommand.cc0000644000175000017500000000031614065623622016733 0ustar frankfrank#include "guncat.ih" void Guncat::showGPGcommand() const { cout << d_options.gpgPath() << " --pinentry-mode loopback --passphrase-fd " << d_options.gpgDecrypt() << '\n'; } guncat-2.00.02/guncat/onlycin.cc0000644000175000017500000000162614065623622015376 0ustar frankfrank#include "guncat.ih" bool Guncat::onlyCin() { Arg &arg = Arg::instance(); switch (arg.nArgs()) { case 1: // 1 argument: if (arg[0] != "-"s) // if not - then its a filename break; [[fallthrough]]; case 0: // no or 1 argument: read stdin g_filename = "stdin"; d_gpgHandler.checkPassphrase(cin); process(cin); return true; default: // multiple args: may not contain - { auto begin = arg.argPointers(); auto end = begin + arg.nArgs(); auto iter = find(begin, end, "-"); delete[] begin; if (iter != end) throw Exception{} << "argument - cannot be mixed with filename arguments"; } break; } return false; } guncat-2.00.02/icmake/0000755000175000017500000000000014065623622013357 5ustar frankfrankguncat-2.00.02/icmake/setopt0000644000175000017500000000034114065623622014616 0ustar frankfrankstring setOpt(string install_im, string envvar) { list optvar; string ret; optvar = getenv(envvar); if (optvar[0] == "1") ret = optvar[1]; else ret = install_im; return ret; } guncat-2.00.02/icmake/manpage0000644000175000017500000000057514065623622014721 0ustar frankfrank#define MANPAGE "../../tmp/man/" ${PROGRAM} ".1" void manpage() { md("tmp/man tmp/manhtml"); chdir("documentation/man"); if (PROGRAM ".yo" younger MANPAGE || "release.yo" younger MANPAGE) { run("yodl2man -o " MANPAGE " " PROGRAM); run("yodl2html -o ../../tmp/manhtml/" PROGRAM ".1.html " PROGRAM); chdir("../.."); } exit(0); } guncat-2.00.02/icmake/findall0000644000175000017500000000123114065623622014710 0ustar frankfrank// assuming we're in g_cwd, all entries of type 'type' matching source/pattern // are returned w/o final \n list findAll(string type, string source, string pattern) { string cmd; list entries; list ret; int idx; chdir(source); cmd = "find ./ -mindepth 1 -maxdepth 1 -type " + type; if (pattern != "") pattern = "-name '" + pattern + "'"; entries = backtick(cmd + " " + pattern + " -printf \"%f\\n\""); idx = listlen(entries); if (idx > 0 && strlen(entries[0]) > 0) { for (idx = listlen(entries); idx--; ) ret += (list)cutEoln(entries[idx]); } chdir(g_cwd); return ret; } guncat-2.00.02/icmake/log0000755000175000017500000000063214065623622014067 0ustar frankfrank#!/bin/bash find tmp/install -type f -exec md5sum "{}" \; | sed 's|tmp/install|'$1'|' > $2 find tmp/install -type l -exec printf "link %s\n" "{}" \; | sed 's|tmp/install|'$1'|' >> $2 find tmp/install -type d -exec printf "dir %s\n" "{}" \; | sed 's|tmp/install|'$1'|' >> $2 guncat-2.00.02/icmake/adddir0000644000175000017500000000112514065623622014530 0ustar frankfranklist addDir(list dir, string entry) { list ret; int idx; int keep = 1; string elem; for (idx = listlen(dir); idx--; ) { elem = dir[idx]; if (strfind(entry, elem) != -1) // entry contains dir, ignore dir ret += (list)entry; else if (strfind(elem, entry) != -1) // dir contains entry { ret += (list)elem; keep = 0; } else // new unique entry, keep dir[idx] ret += (list)elem; } if (keep) ret += (list)entry; return ret; } guncat-2.00.02/icmake/pathfile0000644000175000017500000000055214065623622015100 0ustar frankfranklist path_file(string path) { list ret; int len; int idx; for (len = strlen(path), idx = len; idx--; ) { if (path[idx] == "/") { ret = (list)substr(path, 0, idx) + (list)substr(path, idx + 1, len); return ret; } } ret = (list)"" + (list)path; return ret; } guncat-2.00.02/icmake/clean0000644000175000017500000000043614065623622014367 0ustar frankfrankvoid clean(int dist) { run("rm -rf " "build-stamp configure-stamp " "options/SKEL " "tmp/*.o tmp/*-stamp " + "o */o release.yo tmp/lib*.a " ); if (dist) run("rm -rf tmp *.ih.gch */*.ih.gch"); exit(0); } guncat-2.00.02/icmake/uninstall0000644000175000017500000000045614065623622015320 0ustar frankfrankvoid uninstall(string logfile) { int idx; list entry; string dir; list line; if (!exists(logfile)) { printf("installation log file " + logfile + " not found\n"); exit(0); } run("icmake/remove " + logfile + " " + (string)g_echo); exit(0); } guncat-2.00.02/icmake/cuteoln0000644000175000017500000000023314065623622014751 0ustar frankfrankstring cutEoln(string text) { int len; len = strlen(text) - 1; if (text[len] == "\n") text = substr(text, 0, len); return text; } guncat-2.00.02/icmake/run0000644000175000017500000000015114065623622014103 0ustar frankfrankvoid run(string cmd) { if (g_echo == OFF) cmd += "> /dev/null 2>&1"; system(0, cmd); } guncat-2.00.02/icmake/md0000644000175000017500000000074014065623622013703 0ustar frankfrank// md: target should be a series of blank-delimited directories to be created // If an element is a whildcard, the directory will always be created, // using mkdir -p. // // uses: run() void md(string target) { int idx; list paths; string dir; if (!exists(target)) run("mkdir -p " + target); else if (((int)stat(target)[0] & S_IFDIR) == 0) { printf(target + " exists, but is not a directory\n"); exit(1); } } guncat-2.00.02/icmake/gitlab0000644000175000017500000000022114065623622014537 0ustar frankfrankvoid gitlab() { run("cp -r release.yo tmp/manhtml/guncat.1.html ../../wip"); run("cp changelog ../../wip/changelog.txt"); exit(0); } guncat-2.00.02/icmake/remove0000755000175000017500000000117014065623622014601 0ustar frankfrank#!/bin/bash g_echo=$2 rm_f() { [ $g_echo -ne 0 ] && echo rm $1 rm -f $1 } rm_dir() { [ $g_echo -ne 0 ] && echo rmdir $1 rmdir --ignore-fail-on-non-empty -p $1 } IFS=" " for line in `cat $1` do field1=`echo $line | awk '{printf $1}'` field2=`echo $line | awk '{printf $2}'` if [ $field1 == "link" ] ; then rm_f $field2 elif [ $field1 == "dir" ] ; then rm_dir $field2 elif [ -e "$field2" ] ; then if [ "$field1" != "`md5sum $field2 | awk '{printf $1}'`" ] ; then echo $field2 changed, not removed else rm_f $field2 fi fi done rm_f $1 guncat-2.00.02/icmake/precompileheaders0000644000175000017500000000133614065623622017000 0ustar frankfrankstring g_compiler; int g_gch = 1; void _precompile(string class) { string classIH; classIH = class + ".ih"; if (classIH younger class + ".ih.gch") run(g_compiler + " -x c++-header " + classIH); } void precompileHeaders() { int idx; list classes; string class; if (!g_gch) return; classes = makelist(O_SUBDIR, "*"); g_compiler = setOpt(CXX, "CXX") + " " + setOpt(CXXFLAGS, "CXXFLAGS") + " "; _precompile("main"); // precompile the main program .ih file for (idx = listlen(classes); idx--; ) { class = classes[idx]; chdir(class); _precompile(class); chdir(g_cwd); } } guncat-2.00.02/icmake/backtick0000644000175000017500000000016014065623622015052 0ustar frankfranklist backtick(string arg) { list ret; echo(OFF); ret = `arg`; echo(g_echo); return ret; } guncat-2.00.02/icmake/install0000644000175000017500000000332414065623622014752 0ustar frankfrank void install(string request, string dest) { string target; int components = 0; list pathsplit; string base; base = "tmp/install/"; md(base); if (request == "x") components = 63; else { if (strfind(request, "b") != -1) components |= 2; if (strfind(request, "d") != -1) components |= 4; if (strfind(request, "m") != -1) components |= 8; } if (components & 2) { target = base + BINARY; pathsplit = path_file(target); printf(" installing the executable `", target, "'\n"); logFile("tmp/bin", "binary", pathsplit[0], pathsplit[1]); } if (components & (4 | 8)) { target = base + DOC "/"; if (components & 4) { printf(" installing the README and changelog files at `", target, "\n"); logZip("", "changelog README", target ); } if (components & 8) { printf(" installing the html-manual pages at `", target, "\n"); logInstall("tmp/manhtml", "", target); } } if (components & 8) { target = base + MAN "/"; printf(" installing the manual page below `", target, "'\n"); logZip("tmp/man", "guncat.1", target); } chdir(g_cwd); if (dest == "") dest = "/"; else md(dest); dest = cutEoln(backtick("realpath " + dest)[0]); if (g_logPath != "") backtick("icmake/log " + dest + " " + g_logPath); run("tar cf - -Ctmp/install . | tar xf - -C" + dest); printf("\n Installation completed\n"); exit(0); } guncat-2.00.02/icmake/logfile0000644000175000017500000000025714065623622014727 0ustar frankfrankvoid logFile(string srcdir, string src, string destdir, string dest) { chdir(g_cwd); md(destdir); run("cp " + srcdir + "/" + src + " " + destdir + "/" + dest); } guncat-2.00.02/icmake/loginstall0000644000175000017500000000156514065623622015461 0ustar frankfrank// source and dest, absolute or reachable from g_cwd, should exist. // files and links in source matching dest (if empty: all) are copied to dest // and are logged in g_log // Before they are logged, dest is created void logInstall(string src, string pattern, string dest) { list entries; int idx; chdir(g_cwd); md(dest); src += "/"; dest += "/"; if (listlen(makelist(O_DIR, src)) == 0) { printf("Warning: ", src, " not found: can't install ", src, pattern, " at ", dest, "\n"); return; } entries = findAll("f", src, pattern); for (idx = listlen(entries); idx--; ) run("cp " + src + entries[idx] + " " + dest); chdir(g_cwd); entries = findAll("l", src, pattern); for (idx = listlen(entries); idx--; ) run("cp " CPOPTS " " + src + entries[idx] + " " + dest); } guncat-2.00.02/icmake/special0000644000175000017500000000042114065623622014717 0ustar frankfrankvoid special() { if (! exists("release.yo") || "VERSION" newer "release.yo") { system("touch version.cc"); run("gcc -E VERSION.h | grep -v '#' | sed 's/\\\"//g' > " "release.yo"); } } guncat-2.00.02/icmake/logzip0000644000175000017500000000165614065623622014616 0ustar frankfrank// names may be a series of files in src, not a wildcard. // if it's empty then all files in src are used. // the files are gzipped and logged in dest. // src and dest do not have to end in / void logZip(string src, string names, string dest) { list files; int idx; string file; chdir(g_cwd); md(dest); dest += "/"; if (src != "") { if (listlen(makelist(O_DIR, src)) == 0) { printf("Warning: ", src, " not found: can't install ", src, names, " at ", dest, "\n"); return; } chdir(src); } if (names == "") files = makelist("*"); else files = strtok(names, " "); for (idx = listlen(files); idx--; ) { file = files[idx]; run("gzip -n -9 < " + file + " > " + file + ".gz"); } run("tar cf - *.gz | (cd " + g_cwd + "; cd " + dest + "; tar xf -)"); run("rm *.gz"); } guncat-2.00.02/icmconf0000644000175000017500000000100414065623622013462 0ustar frankfrank#include "INSTALL.im" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define LIBRARY "guncat" #define MAIN "main.cc" #define OBJ_EXT ".o" //#define REFRESH #define SHAREDREQ "" #define SOURCES "*.cc" #define TMP_DIR "tmp" //#define USE_ALL "a" #define IH ".ih" #define PRECOMP "-x c++-header" #define USE_ECHO ON #define USE_VERSION #define DEFCOM "program" guncat-2.00.02/icmconf.lib0000644000175000017500000000073414065623622014240 0ustar frankfrank#define PRECOMP "-x c++-header" #define CLS #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "library" guncat-2.00.02/INSTALL0000644000175000017500000000750414065623622013165 0ustar frankfrankTo install guncat by hand instead of using a binary distribution perform the following steps: 0. guncat and its construction depends, in addition to the normally standard available system software on specific software and versions which is documented in the file `required'. (If you compile the bobcat library yourself, note that guncat does not use the SSL, Milter and Xpointer classes; they may --as far as guncat is concerned-- be left out of the library by running './build light') 1. It is expected you use icmake for the package construction. For this a top-level script (build) and support scripts in the ./icmake/ directory are available. By default, the 'build' script echoes the commands it executes to the standard output stream. By specifying the option -q (e.g., ./build -q ...) this is prevented, significantly reducing the output generated by 'build'. 2. Inspect the values of the variables in the file INSTALL.im Modify these when necessary. 3. Run ./build program [strip] to compile guncat. The argument `strip' is optional and strips symbolic information from the final executable. 4. If you installed Yodl then you can create the documentation: ./build man builds the man-page. 5. Before installing the components of guncat, consider defining the environment variable GUNCAT, defining its value as the (preferably absolute) filename of a file on which installed files and directories are logged. Defining the GUNCAT environment variable as ~/.guncat usually works well. 6. Run (probably as root) ./build install 'what' 'base' to install. Here, 'what' specifies what you want to install. Specify: x, to install all components, or specify a combination of: b (binary program), d (standard documentation), m (man-pages) E.g., use ./build install bm 'base' if you only want to be able to run guncat, and want its man-page to be installed below 'base'. ./build install's last argument 'base' is optional: the base directory below which the requested files are installed. This base directory is prepended to the paths #defined in the INSTALL.im file. If 'base' is not specified, then INSTALL.im's #defined paths are used as-is. When requesting non-existing elements (e.g., './build install x' was requested, but the man-pages weren't constructed) then these non-existing elements are silently ignored by the installation process. If the environment variable GUNCAT was defined when issuing the `./build install ...' command then a log of all installed files is written to the file indicated by the GUNCAT environment variable (see also the next item). Defining the GUNCAT environment variable as ~/.guncat usually works well. 7. Uninstalling previously installed components of guncat is easy if the environment variable GUNCAT was defined before issuing the `./build install ...' command. In that case, run the command ./build uninstall logfile where 'logfile' is the file that was written by ./build install. Modified files and non-empty directories are not removed, but the logfile itself is removed following the uninstallation. 8. Following the installation nothing in the directory tree which contains this file (i.e., INSTALL) is required for the proper functioning of guncat, so consider removing it. If you only want to remove left-over files from the build-process, just run ./build distclean guncat-2.00.02/INSTALL.im0000644000175000017500000000212214065623622013560 0ustar frankfrank#define PROGRAM "guncat" #define CXX "g++" #define CXXFLAGS "--std=c++2a -Wall -O2 -fdiagnostics-color=never" // flags passed to the linker #define LDFLAGS "" // The following /bin/cp option is used to keep, rather than follow // symbolic references. If your installation doesn't support these flags, // then change them into available ones. // -P, --no-dereference // never follow symbolic links in SOURCE // --preserve[=ATTR_LIST] // preserve the specified attributes (default: // mode,ownership,timestamps), if possible additional // attributes: context, links, all // -d same as --no-dereference --preserve=links #define CPOPTS "-d" // ONLY USE ABSOLUTE DIRECTORY NAMES: // the final program #define BINARY "/usr/bin/"${PROGRAM} // the directory where the standard documentation is stored #define DOC "/usr/share/doc/"${PROGRAM} // the directory whre the manual page is stored #define MAN "/usr/share/man/man1" guncat-2.00.02/lessfork/0000755000175000017500000000000013772402132013751 5ustar frankfrankguncat-2.00.02/lessfork/xerr/0000755000175000017500000000000013770204670014736 5ustar frankfrankguncat-2.00.02/lessfork/xerr/xerr.ih0000644000175000017500000000131313770204670016236 0ustar frankfrank// define X to activate the xerr/xerr2 macros: // xerr(insertion) // inserts the '<<' concatenated elements into std::cerr // preceded by the name of the source file, and ended by '\n' // xerr2(insertion, code) // performs the insertion if X is defined, and (unconditionally) // executes the statement(s) in `code'. `code' must be valid // C(++) code. // #ifdef XERR #include #define xerr(insertion) std::cerr << __FILE__": " << insertion << '\n' #define xerr2(insertion, b) \ { std::cerr << __FILE__": " << insertion << '\n'; b; } #else #define xerr(insertion) #define xerr2(insertion, b) b #endif guncat-2.00.02/lessfork/demo.cc0000644000175000017500000000060113772372347015217 0ustar frankfrank//#include //#include //#include // //using namespace std; // //struct Data //{ // istream &d_in; // string str // // Data(istream &in) // : // d_in(in) // { // getline(d_in, d_str); // } //}; // //int main() //{ // for (auto [in, str] = Data{cin}; in; getline(in, str)) // ; //process(str); //} // // // // // guncat-2.00.02/lessfork/README0000644000175000017500000001525213772402132014636 0ustar frankfrankSo what's the fun of letting output handle by streams? Reusable code! Once you communicate through streams all your software expecting information from istreams and writing output to ostreams is maintenance free. Let's concentrate on ostreams: - you can write to your screen - you can write to files on disk - you can write (e.g., using TCP/IP) to any computer anywhere in the world - you can write to the syslog - you can write to your friends living on Mars There's no end to the fun. The only thing you need is a stream to which you write as usual, which offers the adaptor to the device you want to send information to. ----------------------------- OForkStream in this archive does exactly that. OForkStream receives lots of information, but it's too much to show in a convenient way on your screen. In such cases the program 'less' is a convenient tool: it allows you to page through your information either by stepping (paging) back or by stepping (paging) forward. ----------------------------- Here's the core problem: we can define a new (o)stream: we've done that, and essentially all it requires is a stream buffer overriding the virtual member 'overflow'. But the problem we must solve is: less doesn't know about overflow, but it knows about its own standard input. Our stream buffer's task is to send each character it receives not to some file, but to less's input. ----------------------------- For that we use pipes. See the pipe(2) man page. But if you read that man-page I guess it won't make your day... But the concept is easy: if you have two processes (like when using fork) then you can create a pipe (before the fork) and then use that pipe to communicate between the two processes: Pre-fork: +-----------------------+ | | | pipe d_pipe | | | +-----------------------+ Post-fork: Parent: Child +-----------------------+ +-----------------------+ | | | | | pipe d_pipe ---------------------------> pipe d_pipe | | | | | +-----------------------+ +-----------------------+ Here the pipe is used to send information from the paretn to the child, and the other direction is also possible (using another pipe) ----------------------------- Pipe-ends (like the reading end at the child or the writing end at the parent) are file-descriptors. OK, we can use write (see the write(2) man-page) to pipes, but that's not funny: write doesn't work like streams. But we can use an existing ostream adaptor: Bobcat's OFdStream: create an OFdStream by passing it a writing-end of a pipe and you can do things like OFdStream ofd{ pipe }; ofd << "hello world" << endl; Doesn't that look familiar? This will nicely stash that familiar string into the pipe. ----------------------------- We're getting close. Concentrate on the child process: +-----------------------+ | | ------------> pipe d_pipe | | (for reading) | | | +-----------------------+ Once we fork, the child process itself calls 'less', right? But just before that we fool less by making it believe it reads its std. input stream while in fact it reads from the pipe: +-----------------------+ +--------------------------+ | | | | ------------> pipe d_pipe ----------------> less (thinks it | | (for reading) | | reads its std. input) | | | | | +-----------------------+ +--------------------------+ That's all, folks. ----------------------------- So how do we fool less? For that we redirect: another interesting Bobcat tool: its Pipe class. - first we create a Bobcat Pipe d_childInput, meaning the that's a pipe that will be used by the child process for reading. - in the parent process we construct an OFdStream, passing it the writing end of Bobcat's Pipe: OFdStream{ d_childInput.writeOnly() }; Since the child reads, the parent uses the writing end of the pipe. - in the child process we redirect the pipe's reading end to the child process's standard input. That happens just before calling less: d_childInput.readFrom(Redirector::STDIN); // or use: STDIN_FILENO ----------------------------- The child process looks a lot like what you've used for the compiler-program: the child process itself is replaced by the less-process, which now nicely reads from our pipe. To call less I didn't struggle with a member of the exec-family but used yet another Bobcat class: Process. ----------------------------- The program ends once we decide that all input has been sent to less. At that point OForkStream goes out of scope, flushing its buffer. Then it dies, immediately followed by the destruction of its stream buffer. That also ends the parent process: its destructor flushes its pipe, then closes its pipe. Less, noticing that it has reached the end of its input quits, and so the streambuf's destructor receives less's exit code via 'waitForChild', and we're done. ----------------------------- So: - we created an ostream - it communicates with its streambuf - its streambuf sets up a pipe - the streambuf's child process is replaced by 'less' - less reads from the pipe - once we're done inserting info into the ostream, the pipe is closed, less ends, and we properly wait for less to end its work Want to write to a different destination: put main's insertions in a function expecting an ostream &, and pass that function, e.g., cout, and OForkStream object, an ofstream object, and .... take your pick. If you want to run the program yourself, either use icmake's 'icmbuild' script or use your own favorite maintenance tool. Essentially: compile all .cc files, and link 'em to the bobcat library. Note that the class Fork (in the ./fork directory) isn't used: no need to compile its sources. ------------------------------ Postscript: In the code you'll find in the tar there's lots of commented out stuff. I didn't construct OForkStream in 5 minutes time. Many of the things I did are still visible in commented-out sections of the source files. guncat-2.00.02/lessfork/oforkstream/0000755000175000017500000000000013770357055016320 5ustar frankfrankguncat-2.00.02/lessfork/oforkstream/oforkstream.ih0000644000175000017500000000010513770355560021171 0ustar frankfrank#include "oforkstream.h" #include using namespace std; guncat-2.00.02/lessfork/oforkstream/oforkstream1.cc0000644000175000017500000000014113770357055021240 0ustar frankfrank//#define XERR #include "oforkstream.ih" OForkStream::OForkStream() : std::ostream(this) {} guncat-2.00.02/lessfork/oforkstream/oforkstream.h0000644000175000017500000000041413770356672021030 0ustar frankfrank#ifndef INCLUDED_OFORKSTREAM_ #define INCLUDED_OFORKSTREAM_ #include #include "../oforkbuf/oforkbuf.h" class OForkStream: private OForkBuf, public std::ostream { public: OForkStream(); ~OForkStream(); private: }; #endif guncat-2.00.02/lessfork/oforkstream/destructor.cc0000644000175000017500000000013113770355315021015 0ustar frankfrank//#define XERR #include "oforkstream.ih" OForkStream::~OForkStream() { // close(); } guncat-2.00.02/lessfork/oforkbuf/0000755000175000017500000000000013770363237015600 5ustar frankfrankguncat-2.00.02/lessfork/oforkbuf/parentprocess.cc0000644000175000017500000000117113770363057020777 0ustar frankfrank#define XERR #include "oforkbuf.ih" void OForkBuf::parentProcess() { d_toChild = new OFdStream{ d_childInput.writeOnly(), 100 }; // for (size_t idx = 0; idx != 100; ++idx) // *d_toChild << "line index " << idx << endl; // // d_childInput.close(); // // cout << "Program ends: " << waitForChild() << '\n'; } //void Less::parentProcess() //{ // xerr(""); // // for (size_t idx = 0; idx != 200; ++idx) // d_toChild << "line index " << idx << endl; // //// d_toChild << "hello world\n"; //// //// d_childInput.close(); // // int ret = waitForChild(); // xerr("Less ends: " << ret); //} // guncat-2.00.02/lessfork/oforkbuf/overflow.cc0000644000175000017500000000033613770362502017746 0ustar frankfrank//#define XERR #include "oforkbuf.ih" int OForkBuf::overflow(int ch) { if (ch != EOF) d_toChild->put(ch); // cout.put(ch); // d_toChild.put(ch); // else // d_less.close(); return ch; } guncat-2.00.02/lessfork/oforkbuf/oforkbuf.h0000644000175000017500000000116413770362146017566 0ustar frankfrank#ifndef INCLUDED_OFORKBUF_ #define INCLUDED_OFORKBUF_ #include #include #include #include class OForkBuf: public std::streambuf, public FBB::Fork { FBB::Pipe d_childInput; FBB::OFdStream *d_toChild; public: OForkBuf(); ~OForkBuf() override; protected: // void close(); private: int overflow(int ch) override; void childRedirections() override; void childProcess() override; void parentProcess() override; }; //inline void OForkBuf::close() //{ // overflow(EOF); //} #endif guncat-2.00.02/lessfork/oforkbuf/childprocess.cc0000644000175000017500000000034313770360772020572 0ustar frankfrank//#define XERR #include "oforkbuf.ih" void OForkBuf::childProcess() { xerr("char: " << cin.get()); Process less{ Process::DIRECT, Process::NO_PATH, "/usr/bin/less" }; less.start(); } guncat-2.00.02/lessfork/oforkbuf/oforkbuf1.cc0000644000175000017500000000011413770361263017776 0ustar frankfrank//#define XERR #include "oforkbuf.ih" OForkBuf::OForkBuf() { fork(); } guncat-2.00.02/lessfork/oforkbuf/childredirections.cc0000644000175000017500000000037113770360726021606 0ustar frankfrank//#define XERR #include "oforkbuf.ih" void OForkBuf::childRedirections() { xerr("child Redirections 1: " << d_childInput.readFd()); d_childInput.readFrom(Redirector::STDIN); xerr("child Redirections 2: " << d_childInput.readFd()); }; guncat-2.00.02/lessfork/oforkbuf/destructor.cc0000644000175000017500000000030313770363237020301 0ustar frankfrank//#define XERR #include "oforkbuf.ih" OForkBuf::~OForkBuf() { d_toChild->flush(); d_childInput.close(); cout << "Program ends: " << waitForChild() << '\n'; delete d_toChild; } guncat-2.00.02/lessfork/oforkbuf/oforkbuf.ih0000644000175000017500000000025313770361665017742 0ustar frankfrank#include "oforkbuf.h" #include "../xerr/xerr.ih" #include #include #include using namespace std; using namespace FBB; guncat-2.00.02/lessfork/icmconf0000644000175000017500000000147113770206201015312 0ustar frankfrank#define CLS //#define LIBRARY "modules" #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" //#define SHARED //#define SHAREDREQ "" #define TMP_DIR "tmp" #define USE_ECHO ON // #define USE_VERSION #define IH ".ih" //#define PRECOMP "-x c++-header" //#define USE_ALL "a" //#define CXX "clang++" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " //#define CC "gcc" //#define CFLAGS " -Wall -O2" #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "program" guncat-2.00.02/lessfork/less/0000755000175000017500000000000013770354655014735 5ustar frankfrankguncat-2.00.02/lessfork/less/put.cc0000644000175000017500000000020413770354441016041 0ustar frankfrank//#define XERR //#include "less.ih" // //void Less::put(int ch) //{ // xerr("put " << (char)ch); // d_toChild.put(ch); //} // guncat-2.00.02/lessfork/less/parentprocess.cc0000644000175000017500000000113013770354373020124 0ustar frankfrank#define XERR #include "less.ih" void Less::parentProcess() { OFdStream toChild(d_childInput.writeOnly(), 100); for (size_t idx = 0; idx != 200; ++idx) toChild << "line index " << idx << endl; d_childInput.close(); cout << "Program ends: " << waitForChild() << '\n'; } //void Less::parentProcess() //{ // xerr(""); // // for (size_t idx = 0; idx != 200; ++idx) // d_toChild << "line index " << idx << endl; // //// d_toChild << "hello world\n"; //// //// d_childInput.close(); // // int ret = waitForChild(); // xerr("Less ends: " << ret); //} // guncat-2.00.02/lessfork/less/childprocess.cc0000644000175000017500000000033313770354312017713 0ustar frankfrank//#define XERR #include "less.ih" void Less::childProcess() { xerr("char: " << cin.get()); Process less{ Process::DIRECT, Process::NO_PATH, "/usr/bin/less" }; less.start(); } guncat-2.00.02/lessfork/less/less1.cc0000644000175000017500000000015413770354655016273 0ustar frankfrank//#define XERR //#include "less.ih" // //Less::Less() //: // d_toChild(d_childInput.writeFd(), 100) //{} guncat-2.00.02/lessfork/less/close.cc0000644000175000017500000000016613770354432016345 0ustar frankfrank//#define XERR //#include "less.ih" // //void Less::close() //{ // xerr("EOF"); // d_childInput.close(); //} // guncat-2.00.02/lessfork/less/less.h0000644000175000017500000000062113770354502016042 0ustar frankfrank#ifndef INCLUDED_LESS_ #define INCLUDED_LESS_ #include #include class Less: public FBB::Fork { FBB::Pipe d_childInput; public: ~Less() override; private: void childRedirections() override; void childProcess() override; void parentProcess() override; }; // void close(); // void put(int ch); #endif guncat-2.00.02/lessfork/less/childredirections.cc0000644000175000017500000000036113770354264020736 0ustar frankfrank//#define XERR #include "less.ih" void Less::childRedirections() { xerr("child Redirections 1: " << d_childInput.readFd()); d_childInput.readFrom(Redirector::STDIN); xerr("child Redirections 2: " << d_childInput.readFd()); }; guncat-2.00.02/lessfork/less/parentredirections.cc0000644000175000017500000000026713770354336021151 0ustar frankfrank//#define XERR //#include "less.ih" // //void Less::parentRedirections() //{ // d_childInput.writeOnly(); // // xerr("parent Redirections: " << d_childInput.writeFd()); //}; // guncat-2.00.02/lessfork/less/destructor.cc0000644000175000017500000000006513770332177017436 0ustar frankfrank//#define XERR #include "less.ih" Less::~Less() {} guncat-2.00.02/lessfork/less/less.ih0000644000175000017500000000025513770354511016216 0ustar frankfrank#include "less.h" #include "../xerr/xerr.ih" #include #include #include using namespace std; using namespace FBB; guncat-2.00.02/lessfork/main.cc0000644000175000017500000000130013772372671015214 0ustar frankfrank//#define XERR #include "main.ih" #include "less/less.h" #include "oforkstream/oforkstream.h" using namespace std; //using namespace FBB; //#include "less.txt" int main(int argc, char **argv) try { cout << "Enter some text, like your name:\n"; string line; getline(cin, line); if (not cin or line.empty()) { cout << "nothing? boring...\n"; return 1; } OForkStream of; for (size_t idx = 0; idx != 200; ++idx) of << "line index " << idx << ": " << line << endl; // Less less; // less.fork(); } catch (exception const &exc) { cerr << exc.what() << '\n'; } catch (...) { cerr << "unexpected exception\n"; return 1; } guncat-2.00.02/lessfork/main.ih0000644000175000017500000000044613770204670015230 0ustar frankfrank#include #include #include //#include #include "xerr/xerr.ih" namespace Icmake { extern char version[]; extern char years[]; extern char author[]; }; using namespace std; //using namespace FBB; void usage(string const &progname); guncat-2.00.02/lessfork/less.txt0000644000175000017500000000160213770354420015463 0ustar frankfrank#include #include #include #include #include using namespace FBB; class Less: public Fork { Pipe d_childInput; public: ~Less() override; private: void childRedirections() override; void childProcess() override; void parentProcess() override; }; Less::~Less() {} void Less::childRedirections() { d_childInput.readFrom(Redirector::STDIN); }; void Less::childProcess() { Process less{ Process::DIRECT, Process::NO_PATH, "/usr/bin/less" }; less.start(); } void Less::parentProcess() { OFdStream toChild(d_childInput.writeOnly(), 100); for (size_t idx = 0; idx != 200; ++idx) toChild << "line index " << idx << endl; d_childInput.close(); cout << "Program ends: " << waitForChild() << '\n'; } guncat-2.00.02/lessfork/CLASSES0000644000175000017500000000003513770361171014774 0ustar frankfrank//less oforkstream oforkbuf guncat-2.00.02/main.cc0000644000175000017500000000153114065623622013361 0ustar frankfrank#include "main.ih" namespace { string terminating{ "Terminating" }; } int main(int argc, char **argv) try { Arg const &arg = prepareArgs(argc, argv); (terminating += ' ') += arg.basename(); arg.versionHelp(usage, version, 0); // no stdin redirection, no files if ( // and not --gpg-command? not Options::instance().gpgCommand() and isatty(STDIN_FILENO) and arg.nArgs() == 0 ) { usage(arg.basename()); throw 1; } Guncat guncat; guncat.run(); // process all files } catch (int x) { return x; } catch (exception const &exc) { cerr << terminating << ": " << exc.what() << '\n'; return 1; } catch (...) { cerr << "Unexpected exception\n"; return 1; } guncat-2.00.02/main.ih0000644000175000017500000000064714065623622013403 0ustar frankfrank#include "xerr/xerr.ih" #include #include #include #include #include "options/options.h" #include "guncat/guncat.h" namespace Icmbuild { extern char version[]; extern char years[]; extern char author[]; }; using namespace std; using namespace FBB; using namespace Icmbuild; Arg const &prepareArgs(int argc, char **argv); void usage(string const &progname); guncat-2.00.02/ooutputstream/0000755000175000017500000000000014065623622015061 5ustar frankfrankguncat-2.00.02/ooutputstream/ooutputstream.ih0000644000175000017500000000010714065623622020334 0ustar frankfrank#include "ooutputstream.h" #include using namespace std; guncat-2.00.02/ooutputstream/ooutputstream.h0000644000175000017500000000051114065623622020162 0ustar frankfrank#ifndef INCLUDED_OOUTPUTSTREAM_ #define INCLUDED_OOUTPUTSTREAM_ #include #include #include "../outputbuf/outputbuf.h" class OOutputStream: private OutputBuf, public std::ostream { public: OOutputStream(std::string const &programName); ~OOutputStream(); private: }; #endif guncat-2.00.02/ooutputstream/ooutputstream1.cc0000644000175000017500000000023414065623622020403 0ustar frankfrank//#define XERR #include "ooutputstream.ih" OOutputStream::OOutputStream(string const &programPath) : OutputBuf(programPath), std::ostream(this) {} guncat-2.00.02/ooutputstream/destructor.cc0000644000175000017500000000013714065623622017567 0ustar frankfrank//#define XERR #include "ooutputstream.ih" OOutputStream::~OOutputStream() { // close(); } guncat-2.00.02/options/0000755000175000017500000000000014065623622013621 5ustar frankfrankguncat-2.00.02/options/instance.cc0000644000175000017500000000025214065623622015733 0ustar frankfrank//#define XERR #include "options.ih" // static Options const &Options::instance() { if (s_options == 0) s_options = new Options(); return *s_options; } guncat-2.00.02/options/data.cc0000644000175000017500000000010414065623622015034 0ustar frankfrank//#define XERR #include "options.ih" Options *Options::s_options; guncat-2.00.02/options/extragpgoptions.cc0000644000175000017500000000062514065623622017370 0ustar frankfrank#include "options.ih" void Options::extraGPGoptions() { if (d_pgpRanges) return; if (string option; size_t nOptions = d_arg.option(&option, "gpg-option")) { (d_gpgDecrypt += ' ') += option; for (size_t idx = 1; idx != nOptions; ++idx) { d_arg.option(idx, &option, "gpg-option"); (d_gpgDecrypt += ' ') += option; } } } guncat-2.00.02/options/options1.cc0000644000175000017500000000334014065623622015704 0ustar frankfrank#define XERR #include "options.ih" Options::Options() : d_arg(Arg::instance()), d_noErrors(d_arg.option(0, "no-errors")), d_passphraseFirstLine(d_arg.option('p')), d_gpgCommand(d_arg.option(0, "gpg-command")), d_pgpRanges(d_arg.option('r')), d_sectionLines(d_arg.option('S')), d_reduceHeaders(d_arg.option('R')), d_skipIncomplete(d_pgpRanges or d_arg.option('s')), d_quotedPrintable(d_arg.option('q')), d_gpgDecrypt(" --no-auto-key-locate --decrypt --batch"), d_gpgSign(" --no-auto-key-locate --quiet --no-tty --batch --sign") { // override default gpg location if (not d_arg.option(&d_gpgPath, "gpg-path")) d_gpgPath = "/usr/bin/gpg"; // get the name of the verbosity d_arg.option(&d_verbose, 'V'); // file if (not d_arg.option('t')) // by default --no-tty is used d_gpgDecrypt += " --no-tty"; if (string timeLimit; d_arg.option(&timeLimit, 'T')) d_timeLimit = stoul(timeLimit); extraGPGoptions(); // add extra gpg options bool less = d_arg.option('l'); // --less was specified d_arg.option(&d_writePath, 'W'); if (d_arg.option(&d_pipePath, 'P') and (not d_writePath.empty() or less)) throw Exception{} << "options --less, --pipe and --write are mutually exclusive"; if (less) d_pipePath = "/usr/bin/less"; else if ( error_code ec; not d_writePath.empty() and fs::exists(d_writePath, ec) ) throw Exception{} << "--write " << d_writePath << ": file already exists"; } guncat-2.00.02/options/icmconf0000644000175000017500000000007614065623622015165 0ustar frankfrank#define LIBRARY "options" #include "../icmconf.lib" guncat-2.00.02/options/options.h0000644000175000017500000000561014065623622015467 0ustar frankfrank#ifndef INCLUDED_OPTIONS_ #define INCLUDED_OPTIONS_ #include namespace FBB { class Arg; } class Options { FBB::Arg const &d_arg; bool d_noErrors; bool d_passphraseFirstLine; // from 1st input line bool d_gpgCommand; bool d_pgpRanges; bool d_sectionLines; bool d_reduceHeaders; bool d_skipIncomplete; bool d_quotedPrintable; std::string d_gpgDecrypt; // options for decrypting std::string d_gpgSign; // options for signing std::string d_gpgPath; std::string d_pipePath; std::string d_writePath; std::string d_verbose; size_t d_timeLimit; static Options *s_options; public: static Options const &instance(); bool passphraseFirstLine() const; bool gpgCommand() const; bool pgpRanges() const; // only report PGP section ranges bool reduceHeaders() const; bool sectionLines() const; // skip incomplete PGP sections bool skipIncomplete() const; // (implied by pgpRanges) bool stdOut() const; bool quotedPrintable() const; bool noErrors() const; std::string const &gpgDecrypt() const; std::string const &gpgSign() const; std::string const &gpgPath() const; std::string const &pipePath() const; std::string const &writePath() const; std::string const &verbose() const; size_t timeLimit() const; private: Options(); void extraGPGoptions(); // add --gpg-option values }; inline bool Options::passphraseFirstLine() const { return d_passphraseFirstLine; } inline bool Options::gpgCommand() const { return d_gpgCommand; } inline bool Options::pgpRanges() const { return d_pgpRanges; } inline bool Options::reduceHeaders() const { return d_reduceHeaders; } inline bool Options::sectionLines() const { return d_sectionLines; } inline bool Options::quotedPrintable() const { return d_quotedPrintable; } inline bool Options::skipIncomplete() const { return d_skipIncomplete; } inline bool Options::noErrors() const { return d_noErrors; } inline bool Options::stdOut() const { return d_pipePath.empty() and d_writePath.empty(); } inline std::string const &Options::pipePath() const { return d_pipePath; } inline std::string const &Options::writePath() const { return d_writePath; } inline std::string const &Options::gpgSign() const { return d_gpgSign; } inline std::string const &Options::gpgDecrypt() const { return d_gpgDecrypt; } inline std::string const &Options::gpgPath() const { return d_gpgPath; } inline std::string const &Options::verbose() const { return d_verbose; } inline size_t Options::timeLimit() const { return d_timeLimit; } #endif guncat-2.00.02/options/options.ih0000644000175000017500000000030114065623622015630 0ustar frankfrank#include "options.h" #include "../xerr/xerr.ih" #include #include #include using namespace std; using namespace FBB; namespace fs = filesystem; guncat-2.00.02/options/driver/0000755000175000017500000000000014065623622015114 5ustar frankfrankguncat-2.00.02/options/driver/icmconf0000644000175000017500000000103314065623622016452 0ustar frankfrank#define CLS #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "guncat bobcat" #define ADD_LIBRARY_PATHS "../../../tmp" #define DEFCOM "program" guncat-2.00.02/options/driver/main.cc0000644000175000017500000000174614065623622016357 0ustar frankfrank#include "main.ih" namespace { string terminating{ "Terminating" }; } int main(int argc, char **argv) try { Arg const &arg = prepareArgs(argc, argv); (terminating += ' ') += arg.basename(); Options const &options = Options::instance(); cout << "getPassphrase: " << options.getPassphrase() << "\n" "pgpRanges: " << options.pgpRanges() << "\n" "noErrors: " << options.noErrors() << "\n" "gpgPath: " << options.gpgPath() << "\n" "gpgOptions: " << options.gpgOptions() << "\n" "gpgProgram: " << options.gpgProgram() << "\n" "msgName: " << options.msgName() << "\n" "verbose: " << options.verbose() << '\n'; } catch (int x) { cerr << "returning " << x << '\n'; return 0; } catch (exception const &exc) { cerr << "Terminating" << Arg::instance().basename() << ": " << exc.what() << '\n'; return 1; } catch (...) { cerr << "Unexpected exception\n"; return 1; } guncat-2.00.02/options/driver/main.ih0000644000175000017500000000026414065623622016364 0ustar frankfrank#include #include #include #include "../options.h" using namespace std; using namespace FBB; Arg const &prepareArgs(int argc, char **argv); guncat-2.00.02/outputbuf/0000755000175000017500000000000014065623622014163 5ustar frankfrankguncat-2.00.02/outputbuf/parentprocess.cc0000644000175000017500000000021214065623622017355 0ustar frankfrank#define XERR #include "outputbuf.ih" void OutputBuf::parentProcess() { d_toChild = new OFdStream{ d_childInput.writeOnly(), 100 }; } guncat-2.00.02/outputbuf/overflow.cc0000644000175000017500000000016314065623622016335 0ustar frankfrank//#define XERR #include "outputbuf.ih" int OutputBuf::overflow(int ch) { d_toChild->put(ch); return ch; } guncat-2.00.02/outputbuf/childprocess.cc0000644000175000017500000000025014065623622017151 0ustar frankfrank//#define XERR #include "outputbuf.ih" void OutputBuf::childProcess() { Process binary{ Process::DIRECT, Process::NO_PATH, d_programPath }; binary.start(); } guncat-2.00.02/outputbuf/outputbuf.h0000644000175000017500000000124114065623622016367 0ustar frankfrank#ifndef INCLUDED_OUTPUTBUF_ #define INCLUDED_OUTPUTBUF_ #include #include #include #include #include class OutputBuf: public std::streambuf, public FBB::Fork { std::string d_programPath; FBB::Pipe d_childInput; FBB::OFdStream *d_toChild; public: OutputBuf(std::string const &programPath); ~OutputBuf() override; private: int overflow(int ch) override; void childRedirections() override; void childProcess() override; void parentProcess() override; }; //inline void OutputBuf::close() //{ // overflow(EOF); //} #endif guncat-2.00.02/outputbuf/outputbuf.ih0000644000175000017500000000025414065623622016543 0ustar frankfrank#include "outputbuf.h" #include "../xerr/xerr.ih" #include #include #include using namespace std; using namespace FBB; guncat-2.00.02/outputbuf/childredirections.cc0000644000175000017500000000037314065623622020173 0ustar frankfrank//#define XERR #include "outputbuf.ih" void OutputBuf::childRedirections() { xerr("child Redirections 1: " << d_childInput.readFd()); d_childInput.readFrom(Redirector::STDIN); xerr("child Redirections 2: " << d_childInput.readFd()); }; guncat-2.00.02/outputbuf/outputbuf1.cc0000644000175000017500000000021114065623622016602 0ustar frankfrank//#define XERR #include "outputbuf.ih" OutputBuf::OutputBuf(string const &programPath) : d_programPath(programPath) { fork(); } guncat-2.00.02/outputbuf/destructor.cc0000644000175000017500000000024214065623622016666 0ustar frankfrank//#define XERR #include "outputbuf.ih" OutputBuf::~OutputBuf() { d_toChild->flush(); d_childInput.close(); waitForChild(); delete d_toChild; } guncat-2.00.02/pgp1bin0000644000175000017500000000527213765752140013423 0ustar frankfrank M˺dk׎ ԵFu,$\t=+HԃlbDz/mRa&l1+zPbu:băGWGD8K8%*XaI(;ratSQOō6 '^fǔ`Cn}"]k\8T!izHg Z DnEw "H.# ˉ<$؎XvʓV!|M=ĩVk<_69;Li<tnW9٫hgbQU (|$^_ES1qneV]hM_&'bbr##I(e@D_0V1c\㧪4)(5Lz"@iEa67\̑yFXFSM:Duq:$n2RI{nt'Bw2IޡLm#j ~pɡajz< .>潞]dY)߹r8 z7K_:[#+c+0oɧ%QUǎD?x?Neҧ)GHB gVLevcak>A-kV_9sy.6N4l3tSCD.qTUCtÖLr\#8x]BʪYpfA>GނLD=PlR6Ⱦ:F3I2K%]+T-oK:IGoîSң?io ?Z}`X2"V{}BOYM-ZBm4 LuAG}K[L¾ _2oB[Ly.'2 m7!Cihx0=q0COu(qA#39b^T h.:AW= [< xv~y$ć'!"4qI@ ]T`=zT/Ikۯ6@Ba=i{@(SXh7@OwX9UVQK"[[I(iN04͓вt2]| t7FdёᏎ}+Cϙ- #j@Ɨ4qUMM If.(^ӰD8\,£cACˆhhdCw?;A]dWz"I(nAur<=ecXA".u)ěk&: ?aѠKEK*"5RkXaR)J[ ŝSnƚ<JhQiQfބ&HT[sE-tA?}n) %p<_ɖYKvn+Is-Q2j%$31WReAWԋBnŀx>͔]~6p5WnY .eP_BCrKa@ۤѼǖў̌ήui[ˁt?L 9gl% /Jsm!9WUW|B:gL0L#LV>¢9[xmi $oP{_B9ub*.3DBo0<νj֪޻ ;-LQ9Ԭ \9crKa(je!2NCAf46OtUGX;?ٽ>PB݃E#oprCNX@͛*w)΁km)R|]hcPw(זp[gMbgX^'fM$mo2̍zU"J|U7dc\q/d(Idg/i,긍o-ra&"Xތ\XT&X3m-@p8@C\$D Y 9gFsv] =-97 S@ce%K%m"3h>&ڙO #include #include // determine the next pgp section and its line numbers class PGPSection { FBB::TempStream d_tempStream; std::istream &d_in; // current input file size_t d_entryOffset; // initial d_in offset size_t d_offset; // location (so far) in d_in size_t d_firstLine; // first line nr. of a PGP section // line nr after recognizing a correct size_t d_nextNr; // PGP section element std::string d_line; // line read by nextLine() // true if the only the section lines bool d_pgpRanges; // should be reported public: PGPSection(std::istream &in); // verify whether a PGP MESSAGE is bool verify(std::ostream &out); // encountered at the in-stream // only if prepare() returns true: // returns the istream containing std::istream &str(); // the PGP MESSAGE section // line-range of the current PGP section std::pair range() const; private: // in PGP section lines all chars must be bool validChars() const; // printable and may not be blanks bool nextLine(); void next(); bool empty(); bool lines(); bool lastLine(); bool endMessage(); void verbose(std::string const &what) const; }; inline std::pair PGPSection::range() const { return { d_firstLine, d_nextNr + 1 }; } #endif guncat-2.00.02/pgpsection/lastline.cc0000644000175000017500000000114114065623622016420 0ustar frankfrank//#define XERR #include "pgpsection.ih" bool PGPSection::lastLine() { if (d_line.front() != '=') // not yet at the last line { // (only once) nextLine(); if (not validChars()) return false; } if (d_line.front() == '=') // at the last line { next(); // another line must follow nextLine(); // the reduced line return true; } verbose("invalid end of the encrypted section"); return false; } guncat-2.00.02/pgpsection/validchars.cc0000644000175000017500000000045014065623622016727 0ustar frankfrank//#define XERR #include "pgpsection.ih" bool PGPSection::validChars() const { for (int ch: d_line) { if (isblank(ch) or not isprint(ch)) { verbose("invalid character(s) in the encrypted section"); return false; } } return true; } guncat-2.00.02/pgpsection/next.cc0000644000175000017500000000017314065623622015567 0ustar frankfrank//#define XERR #include "pgpsection.ih" void PGPSection::next() { d_offset = d_in.tellg(); d_nextNr = g_lineNr; } guncat-2.00.02/pgpsection/verbose.cc0000644000175000017500000000037514065623622016262 0ustar frankfrank//#define XERR #include "pgpsection.ih" void PGPSection::verbose(string const &what) const { if (g_verbose != 0) *g_verbose << g_filename << ':' << d_firstLine << ':' << g_lineNr << ": PGP MESSAGE: " << what << '\n'; } guncat-2.00.02/pgpsection/lines.cc0000644000175000017500000000076014065623622015725 0ustar frankfrank//#define XERR #include "pgpsection.ih" bool PGPSection::lines() { size_t length = d_line.length(); while (nextLine()) { if (not validChars()) return false; // stop at a line of different if (length != d_line.length()) // length { next(); return true; } } return false; // there must be a shorter line } guncat-2.00.02/pgpsection/icmconf0000644000175000017500000000010114065623622015632 0ustar frankfrank#define LIBRARY "pgpsection" #include "../icmconf.lib" guncat-2.00.02/pgpsection/str.cc0000644000175000017500000000017414065623622015422 0ustar frankfrank//#define XERR #include "pgpsection.ih" istream &PGPSection::str() { d_tempStream.seekg(0); return d_tempStream; } guncat-2.00.02/pgpsection/empty.cc0000644000175000017500000000112414065623622015744 0ustar frankfrank//#define XERR #include "pgpsection.ih" bool PGPSection::empty() { while (true) { if (d_line.empty()) { next(); nextLine(); // get the line beyond the empty line return true; } // empty() also accepts initial // content containing : beyond col. 0 if (size_t pos = d_line.find(':'); pos == 0 or pos == string::npos) break; nextLine(); } verbose("no initial empty line"); return false; } guncat-2.00.02/pgpsection/endmessage.cc0000644000175000017500000000025614065623622016726 0ustar frankfrank//#define XERR #include "pgpsection.ih" bool PGPSection::endMessage() { if (d_line == g_endPGP) return true; verbose("no " + g_endPGP); return false; } guncat-2.00.02/pgpsection/pgpsection.ih0000644000175000017500000000041114065623622016772 0ustar frankfrank#include "pgpsection.h" #include "../xerr/xerr.ih" #include #include #include #include #include #include "../globals/globals.h" #include "../options/options.h" using namespace std; using namespace FBB; guncat-2.00.02/pgpsection/pgpsection1.cc0000644000175000017500000000041614065623622017045 0ustar frankfrank//#define XERR #include "pgpsection.ih" PGPSection::PGPSection(istream &in) : d_in(in), d_entryOffset(in.tellg()), d_offset(d_entryOffset) { Options const &options = Options::instance(); d_pgpRanges = options.pgpRanges() | options.sectionLines(); } guncat-2.00.02/pgpsection/verify.cc0000644000175000017500000000150414065623622016114 0ustar frankfrank//#define XERR #include "pgpsection.ih" bool PGPSection::verify(ostream &out) { d_tempStream << g_beginPGP << '\n'; d_firstLine = g_lineNr; next(); // BEGIN PGP MESSAGE has already been read nextLine(); if ( empty() and lines() and lastLine() and endMessage() ) { if (d_pgpRanges) { ostringstream str; str << g_filename << ':' << d_firstLine << ':' << g_lineNr << ": PGP MESSAGE"; starred(out, str.str()); } verbose("complete"); return true; } if (d_offset != 0) { if (not d_in.seekg(d_offset)) throw Exception{} << "repositioning failed"; g_lineNr = d_nextNr; } return false; } guncat-2.00.02/pgpsection/driver/0000755000175000017500000000000014065623622015574 5ustar frankfrankguncat-2.00.02/pgpsection/driver/icmconf0000644000175000017500000000103314065623622017132 0ustar frankfrank#define CLS #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "guncat bobcat" #define ADD_LIBRARY_PATHS "../../../tmp" #define DEFCOM "program" guncat-2.00.02/pgpsection/driver/main.cc0000644000175000017500000000137714065623622017037 0ustar frankfrank#include "main.ih" namespace { string terminating{ "Terminating" }; } int main(int argc, char **argv) try { if (argc == 1) { cout << "provide the filename containing PGP MESSAGEs\n"; return 1; } Arg const &arg = prepareArgs(argc, argv); (terminating += ' ') += arg.basename(); ifstream in{ arg[0] }; PGPSection section(in); string line; while (getline(in, line)) { ++g_lineNr; if (line == g_beginPGP) section.verify(); } } catch (int x) { cerr << "returning " << x << '\n'; return 0; } catch (exception const &exc) { cerr << terminating << ": " << exc.what() << '\n'; return 1; } catch (...) { cerr << "Unexpected exception\n"; return 1; } guncat-2.00.02/pgpsection/driver/main.ih0000644000175000017500000000043514065623622017044 0ustar frankfrank#include #include #include #include #include "../../globals/globals.h" #include "../../options/options.h" #include "../../pgpsection/pgpsection.h" using namespace std; using namespace FBB; Arg const &prepareArgs(int argc, char **argv); guncat-2.00.02/prepareargs.cc0000644000175000017500000000264014065623622014752 0ustar frankfrank#include using namespace FBB; // initializing FBB::Arg is separated from main() so it can be used by // the various driver programs: they declare // // Arg const &prepareArgs(int argc, char **argv); namespace { Arg::LongOption longOptions[] = { Arg::LongOption("gpg-command", Arg::None), Arg::LongOption("gpg-path", Arg::Required), Arg::LongOption("gpg-option", Arg::Required), Arg::LongOption("help", 'h'), Arg::LongOption("less", 'l'), Arg::LongOption("no-errors", Arg::None), Arg::LongOption("passphrase", 'p'), Arg::LongOption("pipe", 'P'), Arg::LongOption("pgp-ranges", 'r'), Arg::LongOption("quoted-printable", 'q'), Arg::LongOption("reduce-headers", 'R'), Arg::LongOption("section-lines", 'S'), Arg::LongOption("skip-incomplete", 's'), Arg::LongOption("time-limit", 'T'), Arg::LongOption("tty-OK", 't'), Arg::LongOption("verbose", 'V'), Arg::LongOption("version", 'v'), Arg::LongOption("write", 'W'), }; auto longEnd = longOptions + std::size(longOptions); } Arg const &prepareArgs(int argc, char **argv) { return Arg::initialize("hlpP:qRrsStT:vV:W:", longOptions, longEnd, argc, argv); } guncat-2.00.02/README0000644000175000017500000000125314065623622013007 0ustar frankfrankGuncat was designed to tackle a problem encountered with (partially) PGP encrypted files (as encountered, e.g., in mailboxes): the encrypted sections of such files are relatively difficult to browse through. Guncat acts like unix's cat command, but handles (partially) encrypted sections of processed files. Sections of guncat's input files which are surrounded by -----BEGIN PGP MESSAGE----- and -----END PGP MESSAGE----- markers are decrypted before being concatenated to the std. output stream. Guncat's output (i.e., the standard output stream) may subsequently be processed by other programs, like grep or less. April 2014-2020 Frank B. Brokken (f.b.brokken@rug.nl) guncat-2.00.02/README.classes0000644000175000017500000000040114065623622014435 0ustar frankfrankOptions Globals | | +-------------+ | | PGPSection GPGhandler | | +-------------+ OutputBuf | | Decryptor OOutputStream | | +-------------------+ | Guncat | main guncat-2.00.02/required0000644000175000017500000000071114065623622013670 0ustar frankfrankThis file lists non-standard software only. Thus, standard utilities like cp, mv, sed, etc, etc, are not explicitly mentioned. Neither is the gcc compiler explicitly mentioned, but a fairly recent one is assumed. Required software for building Guncat ------------------------------------- libbobcat-dev (>= 4.01.02), To use the provided build-script: icmake (>= 8.00.04) To construct the manual and map-page: yodl (>= 3.06.0) guncat-2.00.02/usage.cc0000644000175000017500000000742114065623622013545 0ustar frankfrank// usage.cc #include "main.ih" namespace { char const info[] = R"R([options] [file(s)] Where: [options] - optional arguments (short options between parentheses): --gpg-command: show the gpg command that would be used, and quit. --gpg-path path: path to the gpg program (default: /usr/bin/gpg). --gpg-option "spec": option `spec' is passed to gpg child processes (multiple --gpg-option options may be specified). --help (-h): provide this help (ends guncat, returning 0). --less (-l): output is written to '/usr/bin/less'. By default output is written to the std. output stream. This option cannot be specified when either option --pipe or option --write is specified. --no-errors: processing ends if an invalid PGP section is encountered or if gpg returns a non-zero exit value. Otherwise processing continues beyond the failing PGP section, reporting the line numbers of the failing PGP section. --passphrase (-p): the passphrase is read (without being echoed) as the first line from the first file processed by guncat (which may be the redirected std input stream; otherwise the passphrase is checked by gpg itself (using gpg-agent). --pipe (-P) Full path to a program receiving guncat's output. By default output is written to the std. output stream. This option cannot be specified when either option --less or option --write is specified. --pgp-ranges (-r): the lines-ranges of complete PGP MESSAGE sections are reported. No additional output is produced. --quoted-printable (-q): merely decrypt PGP messages, keeping their quoted-printable content (by default quoted-printable content like '=3D' is converted to ascii). --reduce-headers (-R): only output the mail headers Cc:, Date:, From:, Subject:, and To:. --section-lines (-S): in the output precede decrypted PGP sections by their line numbers. --skip-incomplete (-s): incomple PGP MESSAGE sections are not outputted. --time-limit (-T) : maximum allowed time in seconds for decrypting an encrypted section (by default: no time limit is used). --tty-OK (-t): by default gpg's option --no-tty is used. --verbose (-V) path: specify - to write additional messages to stderr, otherwise messages are written to `path' (by default messages are suppressed). --version (-v) - show version information (ends guncat, returning 0). --write (-W) path: output is written to 'path'. If 'path' already exists guncat terminates. By default output is written to the std. output stream. This option cannot be specified when either option --less or option --pipe is specified. [file(s)] - file(s) to process. Standard input redirection can also be used. By default the processed information is written to the standard output stream, but may also be written to file (using --write or standard output redirection), or may be sent to a the standard input stream of another program (using --less to use /usr/bin/less or --pipe to specify another program). )R"; } void usage(std::string const &progname) { cout << "\n" << progname << " by " << Icmbuild::author << "\n" << progname << " V" << Icmbuild::version << " " << Icmbuild::years << "\n" "\n" "Usage: " << progname << info; } guncat-2.00.02/VERSION0000644000175000017500000000015314065623622013175 0ustar frankfrank#define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)" #define VERSION "2.00.02" #define YEARS "2014-2021" guncat-2.00.02/version.cc0000644000175000017500000000056314065623622014126 0ustar frankfrank// version.cc #include "main.ih" #include "icmconf" #ifdef USE_VERSION #include "VERSION" #endif #ifndef AUTHOR #define AUTHOR "" #endif #ifndef VERSION #define VERSION "0.00.00" #endif #ifndef YEARS #define YEARS "2012" #endif namespace Icmbuild { char version[] = VERSION; char years[] = YEARS; char author[] = AUTHOR; } guncat-2.00.02/VERSION.h0000644000175000017500000000010414065623622013417 0ustar frankfrank#include "VERSION" SUBST(_CurVers_)(VERSION) SUBST(_CurYrs_)(YEARS) guncat-2.00.02/xerr/0000755000175000017500000000000014065623622013106 5ustar frankfrankguncat-2.00.02/xerr/xerr.ih0000644000175000017500000000133014065623622014405 0ustar frankfrank// define XERR to activate the xerr/xerr(2) macros: // xerr(insertion) // inserts the '<<' concatenated elements into std::cerr // preceded by the name of the source file, and ended by '\n' // xerr2(insertion, code) // performs the insertion if X is defined, and (unconditionally) // executes the statement(s) in `code'. `code' must be valid // C(++) code. // #ifdef XERR #include #define xerr(insertion) std::cerr << __FILE__": " << insertion << '\n' #define xerr2(insertion, code) \ { std::cerr << __FILE__": " << insertion << '\n'; code; } #else #define xerr(insertion) #define xerr2(insertion, code) code #endif