English
Kamil Dudka

Drobné programy (C, C++, C#, ...)

Detail souboru

Jméno:Stáhnoutnntpbackup.cc [Stáhnout]
Umístění: tiny > ISA > nntpbackup
Velikost:5.6 KB
Poslední změna:2022-09-09 13:06

Zdrojový kód

/*
 * file: nntp_client.cc - NNTP protocol layer encapsulation
 * project: nntpbackup (ISA)
 * By Kamil Dudka, xdudka00
 * mailto: xdudka00@gmail.com
 */
 
#include "nntp_client.h"
#include <iostream>
#include <fstream>
 
namespace {
  const char *szAppName= "nntbackup";
  inline void errMsg (const char *szMsg) { std::cerr << szAppName << ": error: " << szMsg << "\n"; }
  inline void errMsg (std::string &msg) { std::cerr << szAppName << ": error: " << msg << "\n"; }
}
 
/**
 * This class parse command-line arguments. It uses direct writing
 * to environment data thrught pointers. Be careful.
 */
class ArgParser {
  public:
    struct Err {};						///< General error exception
    struct ErrHelpNeeded: Err {};				///< User request to print help
    struct ErrCustom: Err {					///< Custom-text exception
      std::string _errMsg;					///< Error message text
      ErrCustom (const char *szMsg): _errMsg (szMsg) {};	///< Exception constructor
    };
 
    /**
     * Class constructor. Parameters are the same as main() function parameters.
     * \param argc Main's argc parameter
     * \param argv Main's argv parameter
     */
    ArgParser (int argc, char *argv[]);
    const char *server() const { return _szServer; }		///< \return Return server address (URL or IP).
    unsigned port() const { return _uPort; }			///< \return Return port number. Return 0 if not present.
    bool nextGroup (const char **pszGroup);			///< \return Return pointer to next group name.
 
  private:
    char *_szServer;
    unsigned _uPort;
    char **_pszCurrent;
};
 
/**
 * NntpClient wrapper. It adds some features to NntpClient class.
 */
class NntpBackup: private NntpClient {
  public:
    struct Err {};
    struct ErrFileOpen: Err {					///< Error opening file for writing
      std::string _fileName;					///< Errorneous file name
      ErrFileOpen (std::string fileName): _fileName (fileName) {}
    };
    /**
     * \param szServer Server address (URL or IP).
     * \param uPort Port number. DEF_NNTP_PORT is used if uPort is zero.
     */
    NntpBackup (const char *szServer, unsigned uPort):
      NntpClient (szServer, uPort ? uPort : NntpClient::DEF_NNTP_PORT)
    {
    }
 
    /**
     * Concatenate all articles in group szGroup and save text to file szGroup.
     * \param szGroup Group name and also file name to save to.
     */
    void groupBackup (const char *szGroup);
};
 
/**
 * Application's main() function.
 * \param argc Number of command-line arguments.
 * \param argv Array of command-line argumnets text strings.
 * \return Return zero if there is no error.
 */
int main (int argc, char *argv[]) try {
  ArgParser args (argc, argv);
  NntpBackup nntp (args.server(), args.port());
 
  bool bAllOk= true;
  const char *szGroup;
  while (args.nextGroup (&szGroup)) {
    try {
      nntp.groupBackup (szGroup);
    }
    catch (NntpProtocol::ErrDot) {
      errMsg ("Article data error");
      bAllOk= false;
    }
    catch (NntpProtocol::ErrCmd err) {
      switch (err._iStatus) {
        case 411: {
          // no such news group
          std::string msg ("News group \'");
          msg.append (szGroup);
          msg.append ("\' not found on server");
          errMsg (msg);
          break;
        }
        default: throw;
      }
      bAllOk= false;
    }
    catch (NntpBackup::ErrFileOpen err) {
      std::string msg("Could not open \'");
      msg.append (err._fileName);
      msg.append ("\' for writing");
      errMsg (msg);
      bAllOk= false;
    }
  } // while
 
  return bAllOk ? 0 : -1;
}
catch (ArgParser::ErrHelpNeeded) {
  std::cout <<
    "nntpbackup <host>[:<port>] <group_1> [...<group_n>]\n"
    "  host (obligatory) is an address of NNTP server (IP or name)\n"
    "  port (optional) is port number, on which server listen, default is standrad NNTP port (119)\n"
    "  group_1...group_n (obligatory) are names of news groups, which should be backed up. "
    "At least one news group has to be placed.\n";
  return 0;
}
catch (ArgParser::ErrCustom err) {
  errMsg (err._errMsg);
  return -1;
}
catch (TcpConnection::ErrConnect) {
  errMsg ("Could not connect to remote server");
  return -1;
}
catch (TcpConnection::Err) {
  errMsg ("Connection error (TCP layer)");
  return -1;
}
catch (NntpProtocol::ErrConnect) {
  errMsg ("Connection refused by server (NNTP layer)");
  return -1;
}
catch (NntpProtocol::Err) {
  errMsg ("Comunication error (NNTP layer)");
  return -1;
}
 
ArgParser::ArgParser (int argc, char *argv[]):
  _uPort (0)
{
  if (argc <2 || 0==strcmp ("--help", argv [1]))
    throw ErrHelpNeeded();
  if (argc <3)
    throw ErrCustom ("Missing argument");
 
  _szServer= argv [1];
  _pszCurrent= argv+2;
 
  std::string srvString (_szServer);
  size_t iColon= srvString.find (':');
  if (std::string::npos!= iColon) {
    _szServer [iColon]= '\0';
    char tmp;
    if (1!= sscanf (_szServer+iColon+1, "%u%c", &_uPort, &tmp))
      throw ErrCustom ("Bad port number format");
  }
}
 
bool ArgParser::nextGroup (const char **pszGroup)
{
  *pszGroup= *_pszCurrent;
  _pszCurrent++;
  return (*pszGroup);
}
 
void NntpBackup::groupBackup (const char *szGroup)
{
  // Select group on server
  groupSelect (szGroup);
 
  /**
   * Opened file wrapper. This should automatically close opened file on an exception.
   */
  class FileWrapper {
    std::ofstream _file;
  public:
    FileWrapper (const char *szFileName):
      _file (szFileName, std::ios::out)
    {
      if (!_file)
        throw ErrFileOpen(szFileName);
    }
    ~FileWrapper()
    {
      _file.close();
    }
    operator std::ostream&()
    {
      if (!_file)
        throw Err();
      return _file;
    }
  } file (szGroup);
 
  // Save all articles in group to file
  while (readNext (file))
    static_cast<std::ostream &>(file) << std::endl;
}