<commit_before>#include "callwindow.h"
#include "ui_callwindow.h"

#include "ui_callingwidget.h"

#include "statisticswindow.h"

#include <QCloseEvent>
#include <QHostAddress>
#include <QtEndian>
#include <QTimer>

const uint16_t MAXOPENPORTS = 42;
const uint16_t PORTSPERPARTICIPANT = 4;

CallWindow::CallWindow(QWidget *parent):
  QMainWindow(parent),
  ui_(new Ui::CallWindow),
  settingsView_(),
  stats_(new StatisticsWindow(this)),
  conference_(this),
  callNeg_(),
  media_(stats_),
  timer_(new QTimer(this)),
  portsOpen_(0)
{
  ui_->setupUi(this);

  // GUI updates are handled solely by timer
  timer_->setInterval(30);
  timer_->setSingleShot(false);
  connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
  connect(timer_, SIGNAL(timeout()), stats_, SLOT(update()));
  timer_->start();

  setWindowTitle("HEVC Conferencing");
}

CallWindow::~CallWindow()
{
  timer_->stop();
  delete timer_;
  stats_->close();
  delete stats_;
  delete ui_;
}

void CallWindow::startStream()
{
  Ui::CallerWidget *ui_widget = new Ui::CallerWidget;
  QWidget* holderWidget = new QWidget;
  ui_widget->setupUi(holderWidget);
  connect(ui_widget->AcceptButton, SIGNAL(clicked()), this, SLOT(acceptCall()));
  connect(ui_widget->DeclineButton, SIGNAL(clicked()), this, SLOT(rejectCall()));

  QObject::connect(&callNeg_, SIGNAL(incomingINVITE(QString, QString)),
                   this, SLOT(incomingCall(QString, QString)));

  QObject::connect(&callNeg_, SIGNAL(callingOurselves(QString, std::shared_ptr<SDPMessageInfo>)),
                   this, SLOT(callOurselves(QString, std::shared_ptr<SDPMessageInfo>)));

  QObject::connect(&callNeg_, SIGNAL(callNegotiated(QString, std::shared_ptr<SDPMessageInfo>,
                                                              std::shared_ptr<SDPMessageInfo>)),
                   this, SLOT(callNegotiated(QString, std::shared_ptr<SDPMessageInfo>,
                                                      std::shared_ptr<SDPMessageInfo>)));

  QObject::connect(&callNeg_, SIGNAL(ringing(QString)),
                   this, SLOT(ringing(QString)));

  QObject::connect(&callNeg_, SIGNAL(ourCallAccepted(QString, std::shared_ptr<SDPMessageInfo>,
                                                               std::shared_ptr<SDPMessageInfo>)),
                   this, SLOT(callNegotiated(QString, std::shared_ptr<SDPMessageInfo>,
                                                      std::shared_ptr<SDPMessageInfo>)));

  QObject::connect(&callNeg_, SIGNAL(ourCallRejected(QString)),
                   this, SLOT(ourCallRejected(QString)));

  QObject::connect(&callNeg_, SIGNAL(callEnded(QString, QString)),
                   this, SLOT(endCall(QString, QString)));

  QObject::connect(&settingsView_, SIGNAL(settingsChanged()),
                   this, SLOT(recordChangedSettings()));

  conferenceMutex_.lock();
  conference_.init(ui_->participantLayout, ui_->participants, ui_widget, holderWidget);
  conferenceMutex_.unlock();

  // TODO move these closer to useagepoint
  QSettings settings;
  QString localName = settings.value("local/Name").toString();
  QString localUsername = settings.value("local/Username").toString();

  callNeg_.init(localName, localUsername);

  QSize resolution = QSize(settings.value("video/ScaledWidth").toInt(),
                           settings.value("video/ScaledHeight").toInt());
  qDebug() << "reso:" << resolution;
  media_.init();
  media_.startCall(ui_->SelfView, resolution);
}

void CallWindow::recordChangedSettings()
{
  // TODO call update settings on everything?
}

void CallWindow::addParticipant()
{
  qDebug() << "User wants to add participant. Ports required:"
           << portsOpen_ + PORTSPERPARTICIPANT << "/" << MAXOPENPORTS;
  if(portsOpen_ <= MAXOPENPORTS - PORTSPERPARTICIPANT)
  {
    QString ip_str = ui_->ip->text();

    Contact con;
    con.contactAddress = ip_str;
    con.name = "Anonymous";
    con.username = "unknown";

    QList<Contact> list;
    list.append(con);

    //start negotiations for this connection

    QList<QString> callIDs = callNeg_.startCall(list);

    for(auto callID : callIDs)
    {
      conferenceMutex_.lock();
      conference_.callingTo(callID, "Contact List Missing!"); // TODO get name from contact list
      conferenceMutex_.unlock();
    }
  }
}

void CallWindow::createParticipant(QString& callID, std::shared_ptr<SDPMessageInfo> peerInfo,
                                   const std::shared_ptr<SDPMessageInfo> localInfo)
{
  qDebug() << "Adding participant to conference.";

  portsOpen_ +=PORTSPERPARTICIPANT;

  QHostAddress address;
  address.setAddress(peerInfo->globalAddress);

  in_addr ip;
  ip.S_un.S_addr = qToBigEndian(address.toIPv4Address());

  conferenceMutex_.lock();
  VideoWidget* view = conference_.addVideoStream(callID);
  conferenceMutex_.unlock();

  if(view == NULL)
  {
    qWarning() << "WARNING: NULL widget got from";
    return;
  }

  // TODO: have these be arrays and send video to all of them in case SDP describes it so
  uint16_t sendAudioPort = 0;
  uint16_t recvAudioPort = 0;
  uint16_t sendVideoPort = 0;
  uint16_t recvVideoPort = 0;

  for(auto media : localInfo->media)
  {
    if(media.type == "audio" && recvAudioPort == 0)
    {
      recvAudioPort = media.port;
    }
    else if(media.type == "video" && recvVideoPort == 0)
    {
      recvVideoPort = media.port;
    }
  }

  for(auto media : peerInfo->media)
  {
    if(media.type == "audio" && sendAudioPort == 0)
    {
      sendAudioPort = media.port;
    }
    else if(media.type == "video" && sendVideoPort == 0)
    {
      sendVideoPort = media.port;
    }
  }

  // TODO send all the media if more than one are specified and if required to more than one participant.
  if(sendAudioPort == 0 || recvAudioPort == 0 || sendVideoPort == 0 || recvVideoPort == 0)
  {
    qWarning() << "WARNING: All media ports were not found in given SDP. SendAudio:" << sendAudioPort
               << "recvAudio:" << recvAudioPort << "SendVideo:" << sendVideoPort << "RecvVideo:" << recvVideoPort;
    return;
  }

  if(stats_)
    stats_->addParticipant(peerInfo->globalAddress,
                           QString::number(sendAudioPort),
                           QString::number(sendVideoPort));

  qDebug() << "Sending mediastreams to:" << peerInfo->globalAddress << "audioPort:" << sendAudioPort
           << "VideoPort:" << sendVideoPort;
  media_.addParticipant(callID, ip, sendAudioPort, recvAudioPort, sendVideoPort, recvVideoPort, view);
}

void CallWindow::openStatistics()
{
  stats_->show();
}

void CallWindow::micState()
{
  bool state = media_.toggleMic();

  if(state)
  {
    ui_->mic->setText("Turn mic off");
  }
  else
  {
    ui_->mic->setText("Turn mic on");
  }
}

void CallWindow::cameraState()
{
  bool state = media_.toggleCamera();
  if(state)
  {
    ui_->camera->setText("Turn camera off");
  }
  else
  {
    ui_->camera->setText("Turn camera on");
  }
}

void CallWindow::closeEvent(QCloseEvent *event)
{
  endAllCalls();

  callNeg_.uninit();
  media_.uninit();

  stats_->hide();
  stats_->finished(0);

  QMainWindow::closeEvent(event);
}

void CallWindow::incomingCall(QString callID, QString caller)
{
  if(portsOpen_ <= MAXOPENPORTS - PORTSPERPARTICIPANT)
  {
    qWarning() << "WARNING: Ran out of ports:" << portsOpen_ << "/" << MAXOPENPORTS;
    rejectCall(); // TODO: send a not possible message instead of reject.
    return;
  }

  conferenceMutex_.lock();
  conference_.incomingCall(callID, caller);
  conferenceMutex_.unlock();
}

void CallWindow::callOurselves(QString callID, std::shared_ptr<SDPMessageInfo> info)
{
  if(portsOpen_ <= MAXOPENPORTS - PORTSPERPARTICIPANT)
  {
    qDebug() << "Calling ourselves, how boring.";
    createParticipant(callID, info, info);
  }
}

void CallWindow::acceptCall()
{
  qDebug() << "We accepted";
  conferenceMutex_.lock();
  QString callID = conference_.acceptNewest();
  conferenceMutex_.unlock();
  callNeg_.acceptCall(callID);
}

void CallWindow::rejectCall()
{
  qDebug() << "We rejected";
  conferenceMutex_.lock();
  QString callID = conference_.rejectNewest();
  conferenceMutex_.unlock();
  callNeg_.rejectCall(callID);
}

void CallWindow::ringing(QString callID)
{
  qDebug() << "call is ringing. TODO: display it to user";
}

void CallWindow::ourCallRejected(QString callID)
{
  qDebug() << "Our Call was rejected. TODO: display it to user";
  conferenceMutex_.lock();
  conference_.removeCaller(callID);
  conferenceMutex_.unlock();
}

void CallWindow::callNegotiated(QString callID, std::shared_ptr<SDPMessageInfo> peerInfo,
                                std::shared_ptr<SDPMessageInfo> localInfo)
{
  qDebug() << "Our call has been accepted.";

  qDebug() << "Sending media to IP:" << peerInfo->globalAddress
           << "to port:" << peerInfo->media.first().port;

  // TODO check the SDP info and do ports and rtp numbers properly
  createParticipant(callID, peerInfo, localInfo);
}

void CallWindow::endCall(QString callID, QString ip)
{
  qDebug() << "Received the end of call message";

  // hack to go around the situation where we are ending our own call
  if(portsOpen_ != 0)
  {
    media_.removeParticipant(callID); // must be ended first because of the view.

    conferenceMutex_.lock();
    conference_.removeCaller(callID);
    conferenceMutex_.unlock();

    stats_->removeParticipant(ip);
    portsOpen_ -= PORTSPERPARTICIPANT;
  }
}

void CallWindow::on_settings_clicked()
{
    settingsView_.show();
}

void CallWindow::endAllCalls()
{
  callNeg_.endAllCalls();

  media_.endAllCalls();
  conferenceMutex_.lock();
  conference_.close();
  conferenceMutex_.unlock();
  portsOpen_ = 0;
}
<commit_msg>Port comparison was the wrong way around in this one. Also rejecting call at this point is not the correct solution.<commit_after>#include "callwindow.h"
#include "ui_callwindow.h"

#include "ui_callingwidget.h"

#include "statisticswindow.h"

#include <QCloseEvent>
#include <QHostAddress>
#include <QtEndian>
#include <QTimer>

const uint16_t MAXOPENPORTS = 42;
const uint16_t PORTSPERPARTICIPANT = 4;

CallWindow::CallWindow(QWidget *parent):
  QMainWindow(parent),
  ui_(new Ui::CallWindow),
  settingsView_(),
  stats_(new StatisticsWindow(this)),
  conference_(this),
  callNeg_(),
  media_(stats_),
  timer_(new QTimer(this)),
  portsOpen_(0)
{
  ui_->setupUi(this);

  // GUI updates are handled solely by timer
  timer_->setInterval(30);
  timer_->setSingleShot(false);
  connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
  connect(timer_, SIGNAL(timeout()), stats_, SLOT(update()));
  timer_->start();

  setWindowTitle("HEVC Conferencing");
}

CallWindow::~CallWindow()
{
  timer_->stop();
  delete timer_;
  stats_->close();
  delete stats_;
  delete ui_;
}

void CallWindow::startStream()
{
  Ui::CallerWidget *ui_widget = new Ui::CallerWidget;
  QWidget* holderWidget = new QWidget;
  ui_widget->setupUi(holderWidget);
  connect(ui_widget->AcceptButton, SIGNAL(clicked()), this, SLOT(acceptCall()));
  connect(ui_widget->DeclineButton, SIGNAL(clicked()), this, SLOT(rejectCall()));

  QObject::connect(&callNeg_, SIGNAL(incomingINVITE(QString, QString)),
                   this, SLOT(incomingCall(QString, QString)));

  QObject::connect(&callNeg_, SIGNAL(callingOurselves(QString, std::shared_ptr<SDPMessageInfo>)),
                   this, SLOT(callOurselves(QString, std::shared_ptr<SDPMessageInfo>)));

  QObject::connect(&callNeg_, SIGNAL(callNegotiated(QString, std::shared_ptr<SDPMessageInfo>,
                                                              std::shared_ptr<SDPMessageInfo>)),
                   this, SLOT(callNegotiated(QString, std::shared_ptr<SDPMessageInfo>,
                                                      std::shared_ptr<SDPMessageInfo>)));

  QObject::connect(&callNeg_, SIGNAL(ringing(QString)),
                   this, SLOT(ringing(QString)));

  QObject::connect(&callNeg_, SIGNAL(ourCallAccepted(QString, std::shared_ptr<SDPMessageInfo>,
                                                               std::shared_ptr<SDPMessageInfo>)),
                   this, SLOT(callNegotiated(QString, std::shared_ptr<SDPMessageInfo>,
                                                      std::shared_ptr<SDPMessageInfo>)));

  QObject::connect(&callNeg_, SIGNAL(ourCallRejected(QString)),
                   this, SLOT(ourCallRejected(QString)));

  QObject::connect(&callNeg_, SIGNAL(callEnded(QString, QString)),
                   this, SLOT(endCall(QString, QString)));

  QObject::connect(&settingsView_, SIGNAL(settingsChanged()),
                   this, SLOT(recordChangedSettings()));

  conferenceMutex_.lock();
  conference_.init(ui_->participantLayout, ui_->participants, ui_widget, holderWidget);
  conferenceMutex_.unlock();

  // TODO move these closer to useagepoint
  QSettings settings;
  QString localName = settings.value("local/Name").toString();
  QString localUsername = settings.value("local/Username").toString();

  callNeg_.init(localName, localUsername);

  QSize resolution = QSize(settings.value("video/ScaledWidth").toInt(),
                           settings.value("video/ScaledHeight").toInt());
  qDebug() << "reso:" << resolution;
  media_.init();
  media_.startCall(ui_->SelfView, resolution);
}

void CallWindow::recordChangedSettings()
{
  // TODO call update settings on everything?
}

void CallWindow::addParticipant()
{
  qDebug() << "User wants to add participant. Ports required:"
           << portsOpen_ + PORTSPERPARTICIPANT << "/" << MAXOPENPORTS;
  if(portsOpen_ <= MAXOPENPORTS - PORTSPERPARTICIPANT)
  {
    QString ip_str = ui_->ip->text();

    Contact con;
    con.contactAddress = ip_str;
    con.name = "Anonymous";
    con.username = "unknown";

    QList<Contact> list;
    list.append(con);

    //start negotiations for this connection

    QList<QString> callIDs = callNeg_.startCall(list);

    for(auto callID : callIDs)
    {
      conferenceMutex_.lock();
      conference_.callingTo(callID, "Contact List Missing!"); // TODO get name from contact list
      conferenceMutex_.unlock();
    }
  }
}

void CallWindow::createParticipant(QString& callID, std::shared_ptr<SDPMessageInfo> peerInfo,
                                   const std::shared_ptr<SDPMessageInfo> localInfo)
{
  qDebug() << "Adding participant to conference.";

  portsOpen_ +=PORTSPERPARTICIPANT;

  QHostAddress address;
  address.setAddress(peerInfo->globalAddress);

  in_addr ip;
  ip.S_un.S_addr = qToBigEndian(address.toIPv4Address());

  conferenceMutex_.lock();
  VideoWidget* view = conference_.addVideoStream(callID);
  conferenceMutex_.unlock();

  if(view == NULL)
  {
    qWarning() << "WARNING: NULL widget got from";
    return;
  }

  // TODO: have these be arrays and send video to all of them in case SDP describes it so
  uint16_t sendAudioPort = 0;
  uint16_t recvAudioPort = 0;
  uint16_t sendVideoPort = 0;
  uint16_t recvVideoPort = 0;

  for(auto media : localInfo->media)
  {
    if(media.type == "audio" && recvAudioPort == 0)
    {
      recvAudioPort = media.port;
    }
    else if(media.type == "video" && recvVideoPort == 0)
    {
      recvVideoPort = media.port;
    }
  }

  for(auto media : peerInfo->media)
  {
    if(media.type == "audio" && sendAudioPort == 0)
    {
      sendAudioPort = media.port;
    }
    else if(media.type == "video" && sendVideoPort == 0)
    {
      sendVideoPort = media.port;
    }
  }

  // TODO send all the media if more than one are specified and if required to more than one participant.
  if(sendAudioPort == 0 || recvAudioPort == 0 || sendVideoPort == 0 || recvVideoPort == 0)
  {
    qWarning() << "WARNING: All media ports were not found in given SDP. SendAudio:" << sendAudioPort
               << "recvAudio:" << recvAudioPort << "SendVideo:" << sendVideoPort << "RecvVideo:" << recvVideoPort;
    return;
  }

  if(stats_)
    stats_->addParticipant(peerInfo->globalAddress,
                           QString::number(sendAudioPort),
                           QString::number(sendVideoPort));

  qDebug() << "Sending mediastreams to:" << peerInfo->globalAddress << "audioPort:" << sendAudioPort
           << "VideoPort:" << sendVideoPort;
  media_.addParticipant(callID, ip, sendAudioPort, recvAudioPort, sendVideoPort, recvVideoPort, view);
}

void CallWindow::openStatistics()
{
  stats_->show();
}

void CallWindow::micState()
{
  bool state = media_.toggleMic();

  if(state)
  {
    ui_->mic->setText("Turn mic off");
  }
  else
  {
    ui_->mic->setText("Turn mic on");
  }
}

void CallWindow::cameraState()
{
  bool state = media_.toggleCamera();
  if(state)
  {
    ui_->camera->setText("Turn camera off");
  }
  else
  {
    ui_->camera->setText("Turn camera on");
  }
}

void CallWindow::closeEvent(QCloseEvent *event)
{
  endAllCalls();

  callNeg_.uninit();
  media_.uninit();

  stats_->hide();
  stats_->finished(0);

  QMainWindow::closeEvent(event);
}

void CallWindow::incomingCall(QString callID, QString caller)
{
  if(portsOpen_ > MAXOPENPORTS - PORTSPERPARTICIPANT)
  {
    qWarning() << "WARNING: Ran out of ports:" << portsOpen_ << "/" << MAXOPENPORTS;
    //rejectCall(); // TODO: send a not possible message instead of reject.
    return;
  }

  conferenceMutex_.lock();
  conference_.incomingCall(callID, caller);
  conferenceMutex_.unlock();
}

void CallWindow::callOurselves(QString callID, std::shared_ptr<SDPMessageInfo> info)
{
  if(portsOpen_ <= MAXOPENPORTS - PORTSPERPARTICIPANT)
  {
    qDebug() << "Calling ourselves, how boring.";
    createParticipant(callID, info, info);
  }
}

void CallWindow::acceptCall()
{
  qDebug() << "We accepted";
  conferenceMutex_.lock();
  QString callID = conference_.acceptNewest();
  conferenceMutex_.unlock();
  callNeg_.acceptCall(callID);
}

void CallWindow::rejectCall()
{
  qDebug() << "We rejected";
  conferenceMutex_.lock();
  QString callID = conference_.rejectNewest();
  conferenceMutex_.unlock();
  callNeg_.rejectCall(callID);
}

void CallWindow::ringing(QString callID)
{
  qDebug() << "call is ringing. TODO: display it to user";
}

void CallWindow::ourCallRejected(QString callID)
{
  qDebug() << "Our Call was rejected. TODO: display it to user";
  conferenceMutex_.lock();
  conference_.removeCaller(callID);
  conferenceMutex_.unlock();
}

void CallWindow::callNegotiated(QString callID, std::shared_ptr<SDPMessageInfo> peerInfo,
                                std::shared_ptr<SDPMessageInfo> localInfo)
{
  qDebug() << "Our call has been accepted.";

  qDebug() << "Sending media to IP:" << peerInfo->globalAddress
           << "to port:" << peerInfo->media.first().port;

  // TODO check the SDP info and do ports and rtp numbers properly
  createParticipant(callID, peerInfo, localInfo);
}

void CallWindow::endCall(QString callID, QString ip)
{
  qDebug() << "Received the end of call message";

  // hack to go around the situation where we are ending our own call
  if(portsOpen_ != 0)
  {
    media_.removeParticipant(callID); // must be ended first because of the view.

    conferenceMutex_.lock();
    conference_.removeCaller(callID);
    conferenceMutex_.unlock();

    stats_->removeParticipant(ip);
    portsOpen_ -= PORTSPERPARTICIPANT;
  }
}

void CallWindow::on_settings_clicked()
{
    settingsView_.show();
}

void CallWindow::endAllCalls()
{
  callNeg_.endAllCalls();

  media_.endAllCalls();
  conferenceMutex_.lock();
  conference_.close();
  conferenceMutex_.unlock();
  portsOpen_ = 0;
}
<|endoftext|>


<commit_before>/* cclive
 * Copyright (C) 2010-2011  Toni Gundogdu <legatvs@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <ccinternal>

#include <fstream>
#include <cstring>

#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

#ifndef foreach
#define foreach BOOST_FOREACH
#endif

#include <ccre>
#include <ccoptions>

namespace cc
{

namespace opts = boost::program_options;
namespace fs   = boost::filesystem;

void
options::exec (int argc, char **argv)
{
  // Path to ccliverc.

#if BOOST_FILESYSTEM_VERSION > 2
  fs::path config_path(fs::current_path());
#else
  fs::path config_path(fs::current_path<fs::path>());
#endif

  const char *home = getenv ("HOME");

  if (home && strlen (home) > 0)
    config_path = fs::system_complete (fs::path (home));

  config_path /=
#ifndef _WIN32
    std::string (".") +
#endif
    std::string ("ccliverc");

  // Construct options.

  opts::options_description generic;

  generic.add_options()
  ("version",
   "Print version and exit")
  ("help",
   "Print help and exit")
  ("license",
   "Print license and exit")
  ("support",
   "Print supported websites and exit")
  ("verbose-libcurl",
   "Turn on libcurl verbose output")
  ("quiet,q",
   "Turn off all output, excl. errors")
#ifdef HAVE_FORK
  ("background,b",
   "Go to background")
#endif
  ("query-formats,F",
   "Query available formats to URL")
  ("format,f",
   opts::value<std::string>()->default_value("default"),
   "Download media format")
  ("continue,c",
   "Resume partially downloaded media")
  ("overwrite,W",
   "Overwrite existing media")
  ("output-file,O",
   opts::value<std::string>(),
   "Write media to arg")
  ("no-download,n",
   "Do not download media, print details")
  ("no-resolve,r",
   "Do not resolve URL redirections")
  ("no-proxy",
   "Do not use HTTP proxy")
  ("log-file",
   opts::value<std::string>()->default_value("cclive_log"),
   "Write log output to arg")
  ("update-interval",
   opts::value<double>()->default_value(1.0),
   "Update interval of progressbar")
  ("config-file",
   opts::value<std::string>(&_config_file)
   ->default_value(config_path.string()),
   "Read args from arg")
  ;

  // Config.

  opts::options_description config ("Configuration");

  config.add_options ()
  ("filename-format",
   opts::value<std::string>()->default_value("%t.%s"),
   "Downloaded media filename format")
  ("output-dir",
   opts::value<std::string>(),
   "Write downloaded media to arg directory")
  ("regexp",
   opts::value<std::string>()->default_value("/(\\w|\\pL|\\s)/g"),
   "Regexp to cleanup media title")
  ("subst", opts::value<std::string>(),
   "Replace matched occurences in filename")
  ("exec", opts::value<std::string>(),
   "Invoke arg after each finished download")
  ("agent",
   opts::value<std::string>()->default_value("Mozilla/5.0"),
   "Identify as arg to HTTP servers")
  ("proxy", opts::value<std::string>(),
   "Use proxy for HTTP connections")
  ("throttle", opts::value<int>()->default_value(0),
   "Do not exceed transfer rate arg KB/s")
  ("connect-timeout", opts::value<int>()->default_value(30),
   "Seconds connecting allowed to take")
  ("transfer-timeout", opts::value<int>()->default_value(0),
   "Seconds transfer allowed to take")
  ("dns-cache-timeout", opts::value<int>()->default_value(60),
   "Seconds DNS resolves kept in memory")
  ("max-retries", opts::value<int>()->default_value(5),
   "Max download attempts before giving up")
  ("retry-wait", opts::value<int>()->default_value(5),
   "Time to wait before retrying")
  ;

  // Hidden.

  opts::options_description hidden;

  hidden.add_options ()
  ("url", opts::value< std::vector<std::string> >(), "url");

  // Visible.

  _visible.add (generic).add (config);

  // Command line options.

  opts::options_description cmdline_options;

  cmdline_options.add (generic).add (config).add (hidden);

  // Config file options.

  opts::options_description config_file_options;

  config_file_options.add (config);

  // Positional.

  opts::positional_options_description p;
  p.add ("url", -1);

  // Parse.

  store(opts::command_line_parser (argc,argv)
        .options (cmdline_options).positional (p).run (), _map);

  notify (_map);

  // Read config.

  std::ifstream ifs (_config_file.c_str ());

  if (ifs)
    {
      store (parse_config_file (ifs, config_file_options), _map);
      notify (_map);
    }

  _verify ();
}

const opts::variables_map& options::map () const
{
  return _map;
}

std::ostream& operator<<(std::ostream& os, const options& o)
{
  return os << o._visible;
}

void
options::_verify ()
{
  std::string empty;

  if (_map.count ("regexp"))
    {
      std::string s = _map["regexp"].as<std::string>();

      if (!cc::re::match (s, empty))
        {
          std::stringstream b;

          b << "--regexp: expects "
            << "`/pattern/flags', for example: \"/(\\w|\\s)/g\"";

          throw std::runtime_error (b.str ());
        }
    }

  if (_map.count ("subst"))
    {
      std::istringstream iss( _map["subst"].as<std::string>());
      std::vector<std::string> v;

      std::copy(
        std::istream_iterator<std::string >(iss),
        std::istream_iterator<std::string >(),
        std::back_inserter<std::vector<std::string> >(v)
      );

      foreach (std::string s, v)
      {
        if (!cc::re::subst (s,empty))
          {
            std::stringstream b;

            b << "--subst: expects " << "`s{old}{new}flags'";

            throw std::runtime_error (b.str ());
          }
      }
    }
}

} // namespace cc

// vim: set ts=2 sw=2 tw=72 expandtab:
<commit_msg>cc/options.cpp: Style changes<commit_after>/* cclive
 * Copyright (C) 2010-2011  Toni Gundogdu <legatvs@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <ccinternal>

#include <fstream>
#include <cstring>

#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

#ifndef foreach
#define foreach BOOST_FOREACH
#endif

#include <ccre>
#include <ccoptions>

namespace cc
{

namespace opts = boost::program_options;
namespace fs   = boost::filesystem;

void options::exec(int argc, char **argv)
{
  // Path to ccliverc.

#if BOOST_FILESYSTEM_VERSION > 2
  fs::path config_path(fs::current_path());
#else
  fs::path config_path(fs::current_path<fs::path>());
#endif

  const char *home = getenv("HOME");

  if (home && strlen(home) > 0)
    config_path = fs::system_complete(fs::path(home));

  config_path /=
#ifndef _WIN32
    std::string(".") +
#endif
    std::string("ccliverc");

  // Construct options.

  opts::options_description generic;

  generic.add_options()
  ("version",
   "Print version and exit")
  ("help",
   "Print help and exit")
  ("license",
   "Print license and exit")
  ("support",
   "Print supported websites and exit")
  ("verbose-libcurl",
   "Turn on libcurl verbose output")
  ("quiet,q",
   "Turn off all output, excl. errors")
#ifdef HAVE_FORK
  ("background,b",
   "Go to background")
#endif
  ("query-formats,F",
   "Query available formats to URL")
  ("format,f",
   opts::value<std::string>()->default_value("default"),
   "Download media format")
  ("continue,c",
   "Resume partially downloaded media")
  ("overwrite,W",
   "Overwrite existing media")
  ("output-file,O",
   opts::value<std::string>(),
   "Write media to arg")
  ("no-download,n",
   "Do not download media, print details")
  ("no-resolve,r",
   "Do not resolve URL redirections")
  ("no-proxy",
   "Do not use HTTP proxy")
  ("log-file",
   opts::value<std::string>()->default_value("cclive_log"),
   "Write log output to arg")
  ("update-interval",
   opts::value<double>()->default_value(1.0),
   "Update interval of progressbar")
  ("config-file",
   opts::value<std::string>(&_config_file)
   ->default_value(config_path.string()),
   "Read args from arg")
  ;

  // Config.

  opts::options_description config("Configuration");

  config.add_options()
  ("filename-format",
   opts::value<std::string>()->default_value("%t.%s"),
   "Downloaded media filename format")
  ("output-dir",
   opts::value<std::string>(),
   "Write downloaded media to arg directory")
  ("regexp",
   opts::value<std::string>()->default_value("/(\\w|\\pL|\\s)/g"),
   "Regexp to cleanup media title")
  ("subst", opts::value<std::string>(),
   "Replace matched occurences in filename")
  ("exec", opts::value<std::string>(),
   "Invoke arg after each finished download")
  ("agent",
   opts::value<std::string>()->default_value("Mozilla/5.0"),
   "Identify as arg to HTTP servers")
  ("proxy", opts::value<std::string>(),
   "Use proxy for HTTP connections")
  ("throttle", opts::value<int>()->default_value(0),
   "Do not exceed transfer rate arg KB/s")
  ("connect-timeout", opts::value<int>()->default_value(30),
   "Seconds connecting allowed to take")
  ("transfer-timeout", opts::value<int>()->default_value(0),
   "Seconds transfer allowed to take")
  ("dns-cache-timeout", opts::value<int>()->default_value(60),
   "Seconds DNS resolves kept in memory")
  ("max-retries", opts::value<int>()->default_value(5),
   "Max download attempts before giving up")
  ("retry-wait", opts::value<int>()->default_value(5),
   "Time to wait before retrying")
  ;

  // Hidden.

  opts::options_description hidden;

  hidden.add_options()
  ("url", opts::value< std::vector<std::string> >(), "url");

  // Visible.

  _visible.add(generic).add(config);

  // Command line options.

  opts::options_description cmdline_options;

  cmdline_options.add(generic).add(config).add(hidden);

  // Config file options.

  opts::options_description config_file_options;

  config_file_options.add(config);

  // Positional.

  opts::positional_options_description p;
  p.add("url", -1);

  // Parse.

  store(opts::command_line_parser(argc,argv)
        .options(cmdline_options).positional(p).run(), _map);

  notify(_map);

  // Read config.

  std::ifstream ifs(_config_file.c_str());

  if (ifs)
    {
      store(parse_config_file(ifs, config_file_options), _map);
      notify(_map);
    }

  _verify();
}

const opts::variables_map& options::map() const
{
  return _map;
}

std::ostream& operator<<(std::ostream& os, const options& o)
{
  return os << o._visible;
}

void options::_verify()
{
  std::string empty;

  if (_map.count("regexp"))
    {
      std::string s = _map["regexp"].as<std::string>();

      if (!cc::re::match(s, empty))
        {
          std::stringstream b;

          b << "--regexp: expects "
            << "`/pattern/flags', for example: \"/(\\w|\\s)/g\"";

          throw std::runtime_error(b.str());
        }
    }

  if (_map.count("subst"))
    {
      std::istringstream iss( _map["subst"].as<std::string>());
      std::vector<std::string> v;

      std::copy(
        std::istream_iterator<std::string >(iss),
        std::istream_iterator<std::string >(),
        std::back_inserter<std::vector<std::string> >(v)
      );

      foreach (std::string s, v)
      {
        if (!cc::re::subst(s,empty))
          {
            std::stringstream b;

            b << "--subst: expects " << "`s{old}{new}flags'";

            throw std::runtime_error(b.str());
          }
      }
    }
}

} // namespace cc

// vim: set ts=2 sw=2 tw=72 expandtab:
<|endoftext|>


<commit_before>/*
 * Run a CGI script.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "cgi_client.hxx"
#include "cgi_quark.h"
#include "cgi_parser.hxx"
#include "pool.hxx"
#include "istream-buffer.h"
#include "async.hxx"
#include "header_parser.hxx"
#include "strutil.h"
#include "stopwatch.h"
#include "strmap.hxx"
#include "http_response.hxx"
#include "fb_pool.hxx"
#include "util/Cast.hxx"

#include <string.h>
#include <stdlib.h>

struct cgi_client {
    struct istream output;

    struct stopwatch *stopwatch;

    struct istream *input;
    struct fifo_buffer *buffer;

    struct cgi_parser parser;

    /**
     * This flag is true while cgi_parse_headers() is calling
     * http_response_handler_ref::InvokeResponse().  In this case,
     * istream_read(cgi->input) is already up in the stack, and must
     * not be called again.
     */
    bool in_response_callback;

    bool had_input, had_output;

    struct async_operation operation;
    struct http_response_handler_ref handler;

    void Abort();
};

/**
 * @return false if the connection has been closed
 */
static bool
cgi_return_response(cgi_client *cgi)
{
    cgi->operation.Finished();

    http_status_t status = cgi_parser_get_status(&cgi->parser);
    struct strmap *headers = cgi_parser_get_headers(&cgi->parser);

    if (http_status_is_empty(status)) {
        /* this response does not have a response body, as indicated
           by the HTTP status code */

        stopwatch_event(cgi->stopwatch, "empty");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        cgi->handler.InvokeResponse(status, headers, nullptr);
        pool_unref(cgi->output.pool);
        return false;
    } else if (cgi_parser_eof(&cgi->parser)) {
        /* the response body is empty */

        stopwatch_event(cgi->stopwatch, "empty");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        cgi->handler.InvokeResponse(status, headers,
                                    istream_null_new(cgi->output.pool));
        pool_unref(cgi->output.pool);
        return false;
    } else {
        stopwatch_event(cgi->stopwatch, "headers");

        cgi->in_response_callback = true;
        cgi->handler.InvokeResponse(status, headers, &cgi->output);
        cgi->in_response_callback = false;
        return cgi->input != nullptr;
    }
}

/**
 * Feed data into the input buffer and continue parsing response
 * headers from it.  After this function returns, the response may
 * have been delivered to the response handler, and the caller should
 * post the rest of the specified buffer to the response body stream.
 *
 * Caller must hold pool reference.
 *
 * @return the number of bytes consumed from the specified buffer
 * (moved to the input buffer), 0 if the object has been closed
 */
static size_t
cgi_feed_headers(cgi_client *cgi, const void *data, size_t length)
{
    assert(!cgi_parser_headers_finished(&cgi->parser));

    size_t max_length;
    void *dest = fifo_buffer_write(cgi->buffer, &max_length);
    assert(dest != nullptr);

    if (length > max_length)
        length = max_length;

    memcpy(dest, data, length);
    fifo_buffer_append(cgi->buffer, length);

    GError *error = nullptr;
    enum completion c = cgi_parser_feed_headers(cgi->output.pool, &cgi->parser,
                                                cgi->buffer, &error);
    switch (c) {
    case C_DONE:
        /* the C_DONE status can only be triggered by new data that
           was just received; therefore, the amount of data still in
           the buffer (= response body) must be smaller */
        assert(fifo_buffer_available(cgi->buffer) < length);

        if (!cgi_return_response(cgi))
            return 0;

        /* don't consider data still in the buffer (= response body)
           as "consumed"; the caller will attempt to submit it to the
           response body handler */
        return length - fifo_buffer_available(cgi->buffer);

    case C_MORE:
        return length;

    case C_ERROR:
        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        cgi->handler.InvokeAbort(error);
        pool_unref(cgi->output.pool);
        return 0;

    case C_CLOSED:
        /* unreachable */
        assert(false);
        return 0;
    }

    /* unreachable */
    assert(false);
    return 0;
}

/**
 * Call cgi_feed_headers() in a loop, to parse as much as possible.
 *
 * Caller must hold pool reference.
 */
static size_t
cgi_feed_headers2(cgi_client *cgi, const char *data, size_t length)
{
    assert(length > 0);
    assert(!cgi_parser_headers_finished(&cgi->parser));

    size_t consumed = 0;

    do {
        size_t nbytes = cgi_feed_headers(cgi, data + consumed,
                                         length - consumed);
        if (nbytes == 0)
            break;

        consumed += nbytes;
    } while (consumed < length && !cgi_parser_headers_finished(&cgi->parser));

    if (cgi->input == nullptr)
        return 0;

    return consumed;
}

/**
 * Caller must hold pool reference.
 */
static size_t
cgi_feed_headers3(cgi_client *cgi, const char *data, size_t length)
{
    size_t nbytes = cgi_feed_headers2(cgi, data, length);

    assert(nbytes == 0 || cgi->input != nullptr);
    assert(nbytes == 0 ||
           !cgi_parser_headers_finished(&cgi->parser) ||
           !cgi_parser_eof(&cgi->parser));

    return nbytes;
}

static size_t
cgi_feed_body(cgi_client *cgi, const char *data, size_t length)
{
    if (cgi_parser_is_too_much(&cgi->parser, length)) {
        stopwatch_event(cgi->stopwatch, "malformed");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);

        GError *error =
            g_error_new_literal(cgi_quark(), 0,
                                "too much data from CGI script");
        istream_deinit_abort(&cgi->output, error);
        return 0;
    }

    cgi->had_output = true;

    size_t nbytes = istream_invoke_data(&cgi->output, data, length);
    if (nbytes > 0 && cgi_parser_body_consumed(&cgi->parser, nbytes)) {
        stopwatch_event(cgi->stopwatch, "end");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        istream_deinit_eof(&cgi->output);
        return 0;
    }

    return nbytes;
}

/*
 * input handler
 *
 */

static size_t
cgi_input_data(const void *data, size_t length, void *ctx)
{
    cgi_client *cgi = (cgi_client *)ctx;

    assert(cgi->input != nullptr);

    cgi->had_input = true;

    if (!cgi_parser_headers_finished(&cgi->parser)) {
        const ScopePoolRef ref(*cgi->output.pool TRACE_ARGS);

        size_t nbytes = cgi_feed_headers3(cgi, (const char *)data, length);

        if (nbytes > 0 && nbytes < length &&
            cgi_parser_headers_finished(&cgi->parser)) {
            /* the headers are finished; now begin sending the
               response body */
            size_t nbytes2 = cgi_feed_body(cgi, (const char *)data + nbytes,
                                           length - nbytes);
            if (nbytes2 > 0)
                /* more data was consumed */
                nbytes += nbytes2;
            else if (cgi->input == nullptr)
                /* the connection was closed, must return 0 */
                nbytes = 0;
        }

        return nbytes;
    } else {
        return cgi_feed_body(cgi, (const char *)data, length);
    }
}

static ssize_t
cgi_input_direct(enum istream_direct type, int fd, size_t max_length,
                 void *ctx)
{
    cgi_client *cgi = (cgi_client *)ctx;

    assert(cgi_parser_headers_finished(&cgi->parser));

    cgi->had_input = true;
    cgi->had_output = true;

    if (cgi_parser_known_length(&cgi->parser) &&
        (off_t)max_length > cgi_parser_available(&cgi->parser))
        max_length = (size_t)cgi_parser_available(&cgi->parser);

    ssize_t nbytes = istream_invoke_direct(&cgi->output, type, fd, max_length);
    if (nbytes > 0 && cgi_parser_body_consumed(&cgi->parser, nbytes)) {
        stopwatch_event(cgi->stopwatch, "end");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_close_handler(cgi->input);
        istream_deinit_eof(&cgi->output);
        return ISTREAM_RESULT_CLOSED;
    }

    return nbytes;
}

static void
cgi_input_eof(void *ctx)
{
    cgi_client *cgi = (cgi_client *)ctx;

    cgi->input = nullptr;

    if (!cgi_parser_headers_finished(&cgi->parser)) {
        stopwatch_event(cgi->stopwatch, "malformed");
        stopwatch_dump(cgi->stopwatch);

        assert(!istream_has_handler(istream_struct_cast(&cgi->output)));

        fb_pool_free(cgi->buffer);

        GError *error =
            g_error_new_literal(cgi_quark(), 0,
                                "premature end of headers from CGI script");
        cgi->handler.InvokeAbort(error);
        pool_unref(cgi->output.pool);
    } else if (cgi_parser_requires_more(&cgi->parser)) {
        stopwatch_event(cgi->stopwatch, "malformed");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);

        GError *error =
            g_error_new_literal(cgi_quark(), 0,
                                "premature end of response body from CGI script");
        istream_deinit_abort(&cgi->output, error);
    } else {
        stopwatch_event(cgi->stopwatch, "end");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_deinit_eof(&cgi->output);
    }
}

static void
cgi_input_abort(GError *error, void *ctx)
{
    cgi_client *cgi = (cgi_client *)ctx;

    stopwatch_event(cgi->stopwatch, "abort");
    stopwatch_dump(cgi->stopwatch);

    cgi->input = nullptr;

    if (!cgi_parser_headers_finished(&cgi->parser)) {
        /* the response hasn't been sent yet: notify the response
           handler */
        assert(!istream_has_handler(istream_struct_cast(&cgi->output)));

        fb_pool_free(cgi->buffer);

        g_prefix_error(&error, "CGI request body failed: ");
        cgi->handler.InvokeAbort(error);
        pool_unref(cgi->output.pool);
    } else {
        /* response has been sent: abort only the output stream */
        fb_pool_free(cgi->buffer);
        istream_deinit_abort(&cgi->output, error);
    }
}

static const struct istream_handler cgi_input_handler = {
    .data = cgi_input_data,
    .direct = cgi_input_direct,
    .eof = cgi_input_eof,
    .abort = cgi_input_abort,
};

/*
 * istream implementation
 *
 */

static inline cgi_client *
istream_to_cgi(struct istream *istream)
{
    return &ContainerCast2(*istream, &cgi_client::output);
}

static off_t
istream_cgi_available(struct istream *istream, bool partial)
{
    cgi_client *cgi = istream_to_cgi(istream);

    if (cgi_parser_known_length(&cgi->parser))
        return cgi_parser_available(&cgi->parser);

    if (cgi->input == nullptr)
        return 0;

    if (cgi->in_response_callback)
        /* this condition catches the case in cgi_parse_headers():
           http_response_handler_ref::InvokeResponse() might
           recursively call istream_read(cgi->input) */
        return (off_t)-1;

    return istream_available(cgi->input, partial);
}

static void
istream_cgi_read(struct istream *istream)
{
    cgi_client *cgi = istream_to_cgi(istream);

    if (cgi->input != nullptr) {
        istream_handler_set_direct(cgi->input, cgi->output.handler_direct);

        /* this condition catches the case in cgi_parse_headers():
           http_response_handler_ref::InvokeResponse() might
           recursively call istream_read(cgi->input) */
        if (cgi->in_response_callback) {
            return;
        }

        const ScopePoolRef ref(*cgi->output.pool TRACE_ARGS);

        cgi->had_output = false;
        do {
            cgi->had_input = false;
            istream_read(cgi->input);
        } while (cgi->input != nullptr && cgi->had_input &&
                 !cgi->had_output);
    }
}

static void
istream_cgi_close(struct istream *istream)
{
    cgi_client *cgi = istream_to_cgi(istream);

    fb_pool_free(cgi->buffer);

    if (cgi->input != nullptr)
        istream_free_handler(&cgi->input);

    istream_deinit(&cgi->output);
}

static const struct istream_class istream_cgi = {
    .available = istream_cgi_available,
    .read = istream_cgi_read,
    .close = istream_cgi_close,
};

/*
 * async operation
 *
 */

inline void
cgi_client::Abort()
{
    assert(input != nullptr);

    fb_pool_free(buffer);
    istream_close_handler(input);
    pool_unref(output.pool);
}

/*
 * constructor
 *
 */

void
cgi_client_new(struct pool *pool, struct stopwatch *stopwatch,
               struct istream *input,
               const struct http_response_handler *handler, void *handler_ctx,
               struct async_operation_ref *async_ref)
{
    assert(pool != nullptr);
    assert(input != nullptr);
    assert(handler != nullptr);

    auto cgi = NewFromPool<cgi_client>(*pool);
    istream_init(&cgi->output, &istream_cgi, pool);

    cgi->stopwatch = stopwatch;
    istream_assign_handler(&cgi->input, input,
                           &cgi_input_handler, cgi, 0);

    cgi->buffer = fb_pool_alloc();

    cgi_parser_init(pool, &cgi->parser);

    cgi->handler.Set(*handler, handler_ctx);

    cgi->operation.Init2<cgi_client>();
    async_ref->Set(cgi->operation);

    istream_read(input);
}
<commit_msg>cgi_client: rename struct using CamelCase<commit_after>/*
 * Run a CGI script.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "cgi_client.hxx"
#include "cgi_quark.h"
#include "cgi_parser.hxx"
#include "pool.hxx"
#include "istream-buffer.h"
#include "async.hxx"
#include "header_parser.hxx"
#include "strutil.h"
#include "stopwatch.h"
#include "strmap.hxx"
#include "http_response.hxx"
#include "fb_pool.hxx"
#include "util/Cast.hxx"

#include <string.h>
#include <stdlib.h>

struct CGIClient {
    struct istream output;

    struct stopwatch *stopwatch;

    struct istream *input;
    struct fifo_buffer *buffer;

    struct cgi_parser parser;

    /**
     * This flag is true while cgi_parse_headers() is calling
     * http_response_handler_ref::InvokeResponse().  In this case,
     * istream_read(cgi->input) is already up in the stack, and must
     * not be called again.
     */
    bool in_response_callback;

    bool had_input, had_output;

    struct async_operation operation;
    struct http_response_handler_ref handler;

    void Abort();
};

/**
 * @return false if the connection has been closed
 */
static bool
cgi_return_response(CGIClient *cgi)
{
    cgi->operation.Finished();

    http_status_t status = cgi_parser_get_status(&cgi->parser);
    struct strmap *headers = cgi_parser_get_headers(&cgi->parser);

    if (http_status_is_empty(status)) {
        /* this response does not have a response body, as indicated
           by the HTTP status code */

        stopwatch_event(cgi->stopwatch, "empty");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        cgi->handler.InvokeResponse(status, headers, nullptr);
        pool_unref(cgi->output.pool);
        return false;
    } else if (cgi_parser_eof(&cgi->parser)) {
        /* the response body is empty */

        stopwatch_event(cgi->stopwatch, "empty");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        cgi->handler.InvokeResponse(status, headers,
                                    istream_null_new(cgi->output.pool));
        pool_unref(cgi->output.pool);
        return false;
    } else {
        stopwatch_event(cgi->stopwatch, "headers");

        cgi->in_response_callback = true;
        cgi->handler.InvokeResponse(status, headers, &cgi->output);
        cgi->in_response_callback = false;
        return cgi->input != nullptr;
    }
}

/**
 * Feed data into the input buffer and continue parsing response
 * headers from it.  After this function returns, the response may
 * have been delivered to the response handler, and the caller should
 * post the rest of the specified buffer to the response body stream.
 *
 * Caller must hold pool reference.
 *
 * @return the number of bytes consumed from the specified buffer
 * (moved to the input buffer), 0 if the object has been closed
 */
static size_t
cgi_feed_headers(CGIClient *cgi, const void *data, size_t length)
{
    assert(!cgi_parser_headers_finished(&cgi->parser));

    size_t max_length;
    void *dest = fifo_buffer_write(cgi->buffer, &max_length);
    assert(dest != nullptr);

    if (length > max_length)
        length = max_length;

    memcpy(dest, data, length);
    fifo_buffer_append(cgi->buffer, length);

    GError *error = nullptr;
    enum completion c = cgi_parser_feed_headers(cgi->output.pool, &cgi->parser,
                                                cgi->buffer, &error);
    switch (c) {
    case C_DONE:
        /* the C_DONE status can only be triggered by new data that
           was just received; therefore, the amount of data still in
           the buffer (= response body) must be smaller */
        assert(fifo_buffer_available(cgi->buffer) < length);

        if (!cgi_return_response(cgi))
            return 0;

        /* don't consider data still in the buffer (= response body)
           as "consumed"; the caller will attempt to submit it to the
           response body handler */
        return length - fifo_buffer_available(cgi->buffer);

    case C_MORE:
        return length;

    case C_ERROR:
        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        cgi->handler.InvokeAbort(error);
        pool_unref(cgi->output.pool);
        return 0;

    case C_CLOSED:
        /* unreachable */
        assert(false);
        return 0;
    }

    /* unreachable */
    assert(false);
    return 0;
}

/**
 * Call cgi_feed_headers() in a loop, to parse as much as possible.
 *
 * Caller must hold pool reference.
 */
static size_t
cgi_feed_headers2(CGIClient *cgi, const char *data, size_t length)
{
    assert(length > 0);
    assert(!cgi_parser_headers_finished(&cgi->parser));

    size_t consumed = 0;

    do {
        size_t nbytes = cgi_feed_headers(cgi, data + consumed,
                                         length - consumed);
        if (nbytes == 0)
            break;

        consumed += nbytes;
    } while (consumed < length && !cgi_parser_headers_finished(&cgi->parser));

    if (cgi->input == nullptr)
        return 0;

    return consumed;
}

/**
 * Caller must hold pool reference.
 */
static size_t
cgi_feed_headers3(CGIClient *cgi, const char *data, size_t length)
{
    size_t nbytes = cgi_feed_headers2(cgi, data, length);

    assert(nbytes == 0 || cgi->input != nullptr);
    assert(nbytes == 0 ||
           !cgi_parser_headers_finished(&cgi->parser) ||
           !cgi_parser_eof(&cgi->parser));

    return nbytes;
}

static size_t
cgi_feed_body(CGIClient *cgi, const char *data, size_t length)
{
    if (cgi_parser_is_too_much(&cgi->parser, length)) {
        stopwatch_event(cgi->stopwatch, "malformed");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);

        GError *error =
            g_error_new_literal(cgi_quark(), 0,
                                "too much data from CGI script");
        istream_deinit_abort(&cgi->output, error);
        return 0;
    }

    cgi->had_output = true;

    size_t nbytes = istream_invoke_data(&cgi->output, data, length);
    if (nbytes > 0 && cgi_parser_body_consumed(&cgi->parser, nbytes)) {
        stopwatch_event(cgi->stopwatch, "end");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_free_handler(&cgi->input);
        istream_deinit_eof(&cgi->output);
        return 0;
    }

    return nbytes;
}

/*
 * input handler
 *
 */

static size_t
cgi_input_data(const void *data, size_t length, void *ctx)
{
    CGIClient *cgi = (CGIClient *)ctx;

    assert(cgi->input != nullptr);

    cgi->had_input = true;

    if (!cgi_parser_headers_finished(&cgi->parser)) {
        const ScopePoolRef ref(*cgi->output.pool TRACE_ARGS);

        size_t nbytes = cgi_feed_headers3(cgi, (const char *)data, length);

        if (nbytes > 0 && nbytes < length &&
            cgi_parser_headers_finished(&cgi->parser)) {
            /* the headers are finished; now begin sending the
               response body */
            size_t nbytes2 = cgi_feed_body(cgi, (const char *)data + nbytes,
                                           length - nbytes);
            if (nbytes2 > 0)
                /* more data was consumed */
                nbytes += nbytes2;
            else if (cgi->input == nullptr)
                /* the connection was closed, must return 0 */
                nbytes = 0;
        }

        return nbytes;
    } else {
        return cgi_feed_body(cgi, (const char *)data, length);
    }
}

static ssize_t
cgi_input_direct(enum istream_direct type, int fd, size_t max_length,
                 void *ctx)
{
    CGIClient *cgi = (CGIClient *)ctx;

    assert(cgi_parser_headers_finished(&cgi->parser));

    cgi->had_input = true;
    cgi->had_output = true;

    if (cgi_parser_known_length(&cgi->parser) &&
        (off_t)max_length > cgi_parser_available(&cgi->parser))
        max_length = (size_t)cgi_parser_available(&cgi->parser);

    ssize_t nbytes = istream_invoke_direct(&cgi->output, type, fd, max_length);
    if (nbytes > 0 && cgi_parser_body_consumed(&cgi->parser, nbytes)) {
        stopwatch_event(cgi->stopwatch, "end");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_close_handler(cgi->input);
        istream_deinit_eof(&cgi->output);
        return ISTREAM_RESULT_CLOSED;
    }

    return nbytes;
}

static void
cgi_input_eof(void *ctx)
{
    CGIClient *cgi = (CGIClient *)ctx;

    cgi->input = nullptr;

    if (!cgi_parser_headers_finished(&cgi->parser)) {
        stopwatch_event(cgi->stopwatch, "malformed");
        stopwatch_dump(cgi->stopwatch);

        assert(!istream_has_handler(istream_struct_cast(&cgi->output)));

        fb_pool_free(cgi->buffer);

        GError *error =
            g_error_new_literal(cgi_quark(), 0,
                                "premature end of headers from CGI script");
        cgi->handler.InvokeAbort(error);
        pool_unref(cgi->output.pool);
    } else if (cgi_parser_requires_more(&cgi->parser)) {
        stopwatch_event(cgi->stopwatch, "malformed");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);

        GError *error =
            g_error_new_literal(cgi_quark(), 0,
                                "premature end of response body from CGI script");
        istream_deinit_abort(&cgi->output, error);
    } else {
        stopwatch_event(cgi->stopwatch, "end");
        stopwatch_dump(cgi->stopwatch);

        fb_pool_free(cgi->buffer);
        istream_deinit_eof(&cgi->output);
    }
}

static void
cgi_input_abort(GError *error, void *ctx)
{
    CGIClient *cgi = (CGIClient *)ctx;

    stopwatch_event(cgi->stopwatch, "abort");
    stopwatch_dump(cgi->stopwatch);

    cgi->input = nullptr;

    if (!cgi_parser_headers_finished(&cgi->parser)) {
        /* the response hasn't been sent yet: notify the response
           handler */
        assert(!istream_has_handler(istream_struct_cast(&cgi->output)));

        fb_pool_free(cgi->buffer);

        g_prefix_error(&error, "CGI request body failed: ");
        cgi->handler.InvokeAbort(error);
        pool_unref(cgi->output.pool);
    } else {
        /* response has been sent: abort only the output stream */
        fb_pool_free(cgi->buffer);
        istream_deinit_abort(&cgi->output, error);
    }
}

static const struct istream_handler cgi_input_handler = {
    .data = cgi_input_data,
    .direct = cgi_input_direct,
    .eof = cgi_input_eof,
    .abort = cgi_input_abort,
};

/*
 * istream implementation
 *
 */

static inline CGIClient *
istream_to_cgi(struct istream *istream)
{
    return &ContainerCast2(*istream, &CGIClient::output);
}

static off_t
istream_cgi_available(struct istream *istream, bool partial)
{
    CGIClient *cgi = istream_to_cgi(istream);

    if (cgi_parser_known_length(&cgi->parser))
        return cgi_parser_available(&cgi->parser);

    if (cgi->input == nullptr)
        return 0;

    if (cgi->in_response_callback)
        /* this condition catches the case in cgi_parse_headers():
           http_response_handler_ref::InvokeResponse() might
           recursively call istream_read(cgi->input) */
        return (off_t)-1;

    return istream_available(cgi->input, partial);
}

static void
istream_cgi_read(struct istream *istream)
{
    CGIClient *cgi = istream_to_cgi(istream);

    if (cgi->input != nullptr) {
        istream_handler_set_direct(cgi->input, cgi->output.handler_direct);

        /* this condition catches the case in cgi_parse_headers():
           http_response_handler_ref::InvokeResponse() might
           recursively call istream_read(cgi->input) */
        if (cgi->in_response_callback) {
            return;
        }

        const ScopePoolRef ref(*cgi->output.pool TRACE_ARGS);

        cgi->had_output = false;
        do {
            cgi->had_input = false;
            istream_read(cgi->input);
        } while (cgi->input != nullptr && cgi->had_input &&
                 !cgi->had_output);
    }
}

static void
istream_cgi_close(struct istream *istream)
{
    CGIClient *cgi = istream_to_cgi(istream);

    fb_pool_free(cgi->buffer);

    if (cgi->input != nullptr)
        istream_free_handler(&cgi->input);

    istream_deinit(&cgi->output);
}

static const struct istream_class istream_cgi = {
    .available = istream_cgi_available,
    .read = istream_cgi_read,
    .close = istream_cgi_close,
};

/*
 * async operation
 *
 */

inline void
CGIClient::Abort()
{
    assert(input != nullptr);

    fb_pool_free(buffer);
    istream_close_handler(input);
    pool_unref(output.pool);
}

/*
 * constructor
 *
 */

void
cgi_client_new(struct pool *pool, struct stopwatch *stopwatch,
               struct istream *input,
               const struct http_response_handler *handler, void *handler_ctx,
               struct async_operation_ref *async_ref)
{
    assert(pool != nullptr);
    assert(input != nullptr);
    assert(handler != nullptr);

    auto cgi = NewFromPool<CGIClient>(*pool);
    istream_init(&cgi->output, &istream_cgi, pool);

    cgi->stopwatch = stopwatch;
    istream_assign_handler(&cgi->input, input,
                           &cgi_input_handler, cgi, 0);

    cgi->buffer = fb_pool_alloc();

    cgi_parser_init(pool, &cgi->parser);

    cgi->handler.Set(*handler, handler_ctx);

    cgi->operation.Init2<CGIClient>();
    async_ref->Set(cgi->operation);

    istream_read(input);
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Copyright (c) 2014-2017 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/chaincoin-config.h>
#endif

#include <chainparams.h>
#include <clientversion.h>
#include <compat.h>
#include <fs.h>
#include <interfaces/chain.h>
#include <rpc/server.h>
#include <init.h>
#include <noui.h>
#include <shutdown.h>
#include <modules/masternode/masternode_config.h>
#include <util/system.h>
#include <httpserver.h>
#include <httprpc.h>
#include <util/strencodings.h>
#include <walletinitinterface.h>

#include <stdio.h>

const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Chaincoin (https://www.chaincoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Chaincoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static void WaitForShutdown()
{
    while (!ShutdownRequested())
    {
        MilliSleep(200);
    }
    Interrupt();
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
static bool AppInit(int argc, char* argv[])
{
    InitInterfaces interfaces;
    interfaces.chain = interfaces::MakeChain();

    bool fRet = false;

    //
    // Parameters
    //
    // If Qt is used, parameters/chaincoin.conf are parsed in qt/chaincoin.cpp's main()
    SetupServerArgs();
    std::string error;
    if (!gArgs.ParseParameters(argc, argv, error)) {
        tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
        return false;
    }

    // Process help and version before taking care about datadir
    if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
        std::string strUsage = PACKAGE_NAME " Daemon version " + FormatFullVersion() + "\n";

        if (gArgs.IsArgSet("-version"))
        {
            strUsage += FormatParagraph(LicenseInfo()) + "\n";
        }
        else
        {
            strUsage += "\nUsage:  chaincoind [options]                     Start " PACKAGE_NAME " Daemon\n";
            strUsage += "\n" + gArgs.GetHelpMessage();
        }

        tfm::format(std::cout, "%s", strUsage.c_str());
        return true;
    }

    try
    {
        if (!fs::is_directory(GetDataDir(false)))
        {
            tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
            return false;
        }
        if (!gArgs.ReadConfigFiles(error, true)) {
            tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str());
            return false;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        try {
            SelectParams(gArgs.GetChainName());
        } catch (const std::exception& e) {
            tfm::format(std::cerr, "Error: %s\n", e.what());
            return false;
        }

        // parse masternode.conf
        std::string strErr;
        if(!masternodeConfig.read(strErr)) {
            tfm::format(stderr,"Error reading masternode configuration file: %s\n", strErr.c_str());
            return false;
        }

        // Error out when loose non-argument tokens are encountered on command line
        for (int i = 1; i < argc; i++) {
            if (!IsSwitchChar(argv[i][0])) {
                tfm::format(std::cerr, "Error: Command line contains unexpected token '%s', see chaincoind -h for a list of options.\n", argv[i]);
                return false;
            }
        }

        // -server defaults to true for chaincoind but not for the GUI so do this here
        gArgs.SoftSetBoolArg("-server", true);
        // Set this early so that parameter interactions go to console
        InitLogging();
        InitParameterInteraction();
        if (!AppInitBasicSetup())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
        if (!AppInitParameterInteraction())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
        if (!AppInitSanityChecks())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
        if (gArgs.GetBoolArg("-daemon", false))
        {
#if HAVE_DECL_DAEMON
#if defined(MAC_OSX)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
            tfm::format(std::cout, "Chaincoin server starting\n");

            // Daemonize
            if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
                tfm::format(std::cerr, "Error: daemon() failed: %s\n", strerror(errno));
                return false;
            }
#if defined(MAC_OSX)
#pragma GCC diagnostic pop
#endif
#else
            tfm::format(std::cerr, "Error: -daemon is not supported on this operating system\n");
            return false;
#endif // HAVE_DECL_DAEMON
        }
        // Lock data directory after daemonization
        if (!AppInitLockDataDirectory())
        {
            // If locking the data directory failed, exit immediately
            return false;
        }
        fRet = AppInitMain(interfaces);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(nullptr, "AppInit()");
    }

    if (!fRet)
    {
        Interrupt();
    } else {
        WaitForShutdown();
    }
    Shutdown(interfaces);

    return fRet;
}

int main(int argc, char* argv[])
{
#ifdef WIN32
    util::WinCmdLineArgs winArgs;
    std::tie(argc, argv) = winArgs.get();
#endif
    SetupEnvironment();

    // Connect chaincoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
<commit_msg>fix config read error<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Copyright (c) 2014-2017 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/chaincoin-config.h>
#endif

#include <chainparams.h>
#include <clientversion.h>
#include <compat.h>
#include <fs.h>
#include <interfaces/chain.h>
#include <rpc/server.h>
#include <init.h>
#include <noui.h>
#include <shutdown.h>
#include <modules/masternode/masternode_config.h>
#include <util/system.h>
#include <httpserver.h>
#include <httprpc.h>
#include <util/strencodings.h>
#include <walletinitinterface.h>

#include <stdio.h>

const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Chaincoin (https://www.chaincoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Chaincoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static void WaitForShutdown()
{
    while (!ShutdownRequested())
    {
        MilliSleep(200);
    }
    Interrupt();
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
static bool AppInit(int argc, char* argv[])
{
    InitInterfaces interfaces;
    interfaces.chain = interfaces::MakeChain();

    bool fRet = false;

    //
    // Parameters
    //
    // If Qt is used, parameters/chaincoin.conf are parsed in qt/chaincoin.cpp's main()
    SetupServerArgs();
    std::string error;
    if (!gArgs.ParseParameters(argc, argv, error)) {
        tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
        return false;
    }

    // Process help and version before taking care about datadir
    if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
        std::string strUsage = PACKAGE_NAME " Daemon version " + FormatFullVersion() + "\n";

        if (gArgs.IsArgSet("-version"))
        {
            strUsage += FormatParagraph(LicenseInfo()) + "\n";
        }
        else
        {
            strUsage += "\nUsage:  chaincoind [options]                     Start " PACKAGE_NAME " Daemon\n";
            strUsage += "\n" + gArgs.GetHelpMessage();
        }

        tfm::format(std::cout, "%s", strUsage.c_str());
        return true;
    }

    try
    {
        if (!fs::is_directory(GetDataDir(false)))
        {
            tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
            return false;
        }
        if (!gArgs.ReadConfigFiles(error, true)) {
            tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str());
            return false;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        try {
            SelectParams(gArgs.GetChainName());
        } catch (const std::exception& e) {
            tfm::format(std::cerr, "Error: %s\n", e.what());
            return false;
        }

        // parse masternode.conf
        std::string strErr;
        if(!masternodeConfig.read(strErr)) {
            tfm::format(std::cerr, "Error reading masternode configuration file: %s\n", strErr.c_str());
            return false;
        }

        // Error out when loose non-argument tokens are encountered on command line
        for (int i = 1; i < argc; i++) {
            if (!IsSwitchChar(argv[i][0])) {
                tfm::format(std::cerr, "Error: Command line contains unexpected token '%s', see chaincoind -h for a list of options.\n", argv[i]);
                return false;
            }
        }

        // -server defaults to true for chaincoind but not for the GUI so do this here
        gArgs.SoftSetBoolArg("-server", true);
        // Set this early so that parameter interactions go to console
        InitLogging();
        InitParameterInteraction();
        if (!AppInitBasicSetup())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
        if (!AppInitParameterInteraction())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
        if (!AppInitSanityChecks())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
        if (gArgs.GetBoolArg("-daemon", false))
        {
#if HAVE_DECL_DAEMON
#if defined(MAC_OSX)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
            tfm::format(std::cout, "Chaincoin server starting\n");

            // Daemonize
            if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
                tfm::format(std::cerr, "Error: daemon() failed: %s\n", strerror(errno));
                return false;
            }
#if defined(MAC_OSX)
#pragma GCC diagnostic pop
#endif
#else
            tfm::format(std::cerr, "Error: -daemon is not supported on this operating system\n");
            return false;
#endif // HAVE_DECL_DAEMON
        }
        // Lock data directory after daemonization
        if (!AppInitLockDataDirectory())
        {
            // If locking the data directory failed, exit immediately
            return false;
        }
        fRet = AppInitMain(interfaces);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(nullptr, "AppInit()");
    }

    if (!fRet)
    {
        Interrupt();
    } else {
        WaitForShutdown();
    }
    Shutdown(interfaces);

    return fRet;
}

int main(int argc, char* argv[])
{
#ifdef WIN32
    util::WinCmdLineArgs winArgs;
    std::tie(argc, argv) = winArgs.get();
#endif
    SetupEnvironment();

    // Connect chaincoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
<|endoftext|>


<commit_before>#include <zmq.hpp>
#include <string>
#include <iostream>
#include <cstdlib>
#include <unistd.h>

static bool IsTrue(std::string s) { return s == "true" || s == "TRUE" || s == "1"; }

class Zink
{
    // Default configuration
    std::string endpoint;
    std::string public_key;
    std::string secret_key;
    bool curve;
    bool print_messages;
    bool print_parts;
    bool print_compact;

    int pause_after;
    int exit_after;

    zmq::context_t &context;
    zmq::socket_t socket;
    size_t message_cnt = 0;

  public:
    Zink(zmq::context_t &context)
            : endpoint("tcp://*:13415"),
              public_key("rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7"),
              secret_key("JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6"),
              curve(false),
              print_messages(true),
              print_parts(false),
              print_compact(false),
              pause_after(-1),
              exit_after(-1),
              context(context),
              socket(context, ZMQ_SUB)
    {
        const char *env;
        if (env = std::getenv("ZINK_ENDPOINT"))
            endpoint = env;

        if (env = std::getenv("ZINK_CURVE"))
            curve = IsTrue(env);

        if (env = std::getenv("ZINK_SECRET_KEY"))
        {
            endpoint = env;
            curve = true;
        }

        if (env = std::getenv("ZINK_PRINT"))
        {
            if (std::string("PARTS") == env)
                print_parts = true;

            if (std::string("COMPACT") == env)
                print_compact = true;
        }

        if (env = std::getenv("ZINK_PAUSE_AFTER"))
            pause_after = std::stoul(env);

        if (env = std::getenv("ZINK_EXIT_AFTER"))
            exit_after = std::stoul(env);

        if (curve)
        {
            socket.setsockopt(ZMQ_CURVE_SECRETKEY, secret_key.c_str(), secret_key.length());
            int curve_server = 1;
            socket.setsockopt(ZMQ_CURVE_SERVER, &curve_server, sizeof(curve_server));
        }

        socket.bind(endpoint.c_str());
        socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);
    }

    void ReceiveMessages()
    {
        while (true)
        {
            if (exit_after != -1 && message_cnt >= exit_after)
            {
                std::cout << std::endl << "Exiting after " << message_cnt << " messages"
                          << std::endl;
                return;
            }

            if (pause_after != -1 && message_cnt >= pause_after)
            {
                std::cout << std::endl << "Pausing after " << message_cnt << " messages"
                          << std::endl;
                pause();
                return;
            }

            ReceiveMessage();
        }
    }

    void ReceiveMessage()
    {
        bool more = true;
        int parts_cnt = 0;
        while (more)
        {
            zmq::message_t message;
            auto rc = socket.recv(&message);
            if (rc)
            {
                parts_cnt++;
                std::string m(reinterpret_cast<const char *>(message.data()), message.size());
                if (print_parts)
                    std::cout << "PART " << parts_cnt << ": " << m << std::endl;
                more = message.more();
            }
        }

        message_cnt++;

        if (print_compact)
        {
            std::cout << "." << std::flush;
            if (message_cnt % 100 == 0)
                std::cout << std::endl << message_cnt << " " << std::flush;
        }
        else if (print_messages)
            std::cout << "Message " << message_cnt << " with " << parts_cnt
                      << (parts_cnt > 1 ? " parts" : " part") << std::endl;
    }
};

int main(int argc, char **argv)
{
    zmq::context_t context(1);

    Zink z(context);
    z.ReceiveMessages();
}
<commit_msg>Remove more in-class initialization<commit_after>#include <zmq.hpp>
#include <string>
#include <iostream>
#include <cstdlib>
#include <unistd.h>

static bool IsTrue(std::string s) { return s == "true" || s == "TRUE" || s == "1"; }

class Zink
{
    // Default configuration
    std::string endpoint;
    std::string public_key;
    std::string secret_key;
    bool curve;
    bool print_messages;
    bool print_parts;
    bool print_compact;

    int pause_after;
    int exit_after;

    zmq::context_t &context;
    zmq::socket_t socket;
    size_t message_cnt;

  public:
    Zink(zmq::context_t &context)
            : endpoint("tcp://*:13415"),
              public_key("rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7"),
              secret_key("JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6"),
              curve(false),
              print_messages(true),
              print_parts(false),
              print_compact(false),
              pause_after(-1),
              exit_after(-1),
              context(context),
              socket(context, ZMQ_SUB),
              message_cnt(0)
    {
        const char *env;
        if (env = std::getenv("ZINK_ENDPOINT"))
            endpoint = env;

        if (env = std::getenv("ZINK_CURVE"))
            curve = IsTrue(env);

        if (env = std::getenv("ZINK_SECRET_KEY"))
        {
            endpoint = env;
            curve = true;
        }

        if (env = std::getenv("ZINK_PRINT"))
        {
            if (std::string("PARTS") == env)
                print_parts = true;

            if (std::string("COMPACT") == env)
                print_compact = true;
        }

        if (env = std::getenv("ZINK_PAUSE_AFTER"))
            pause_after = std::stoul(env);

        if (env = std::getenv("ZINK_EXIT_AFTER"))
            exit_after = std::stoul(env);

        if (curve)
        {
            socket.setsockopt(ZMQ_CURVE_SECRETKEY, secret_key.c_str(), secret_key.length());
            int curve_server = 1;
            socket.setsockopt(ZMQ_CURVE_SERVER, &curve_server, sizeof(curve_server));
        }

        socket.bind(endpoint.c_str());
        socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);
    }

    void ReceiveMessages()
    {
        while (true)
        {
            if (exit_after != -1 && message_cnt >= exit_after)
            {
                std::cout << std::endl << "Exiting after " << message_cnt << " messages"
                          << std::endl;
                return;
            }

            if (pause_after != -1 && message_cnt >= pause_after)
            {
                std::cout << std::endl << "Pausing after " << message_cnt << " messages"
                          << std::endl;
                pause();
                return;
            }

            ReceiveMessage();
        }
    }

    void ReceiveMessage()
    {
        bool more = true;
        int parts_cnt = 0;
        while (more)
        {
            zmq::message_t message;
            auto rc = socket.recv(&message);
            if (rc)
            {
                parts_cnt++;
                std::string m(reinterpret_cast<const char *>(message.data()), message.size());
                if (print_parts)
                    std::cout << "PART " << parts_cnt << ": " << m << std::endl;
                more = message.more();
            }
        }

        message_cnt++;

        if (print_compact)
        {
            std::cout << "." << std::flush;
            if (message_cnt % 100 == 0)
                std::cout << std::endl << message_cnt << " " << std::flush;
        }
        else if (print_messages)
            std::cout << "Message " << message_cnt << " with " << parts_cnt
                      << (parts_cnt > 1 ? " parts" : " part") << std::endl;
    }
};

int main(int argc, char **argv)
{
    zmq::context_t context(1);

    Zink z(context);
    z.ReceiveMessages();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <array>
#include <cmath>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h>
using namespace cv;
CGEventRef move;
int main()
{
	while(true)
	{
		moveCursor(getEyePos());
	}
	return 0;
}
void moveCursor(int x, y)
{
	move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, CGPointMake(200, 200), kCGMouseButtonLeft);
}
std::array<int, 2> getEyePos(std::string LR)
{
	std::array eyePosition
	return eyePosition;
}<commit_msg>TempStash<commit_after>#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <array>
#include <cmath>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h>
using namespace cv;
CGEventRef move;
int main()
{
	while(true)
	{
		moveCursor(getEyePos());
	}
	return 0;
}
void moveCursor(int x, y)
{
	move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, CGPointMake(200, 200), kCGMouseButtonLeft);
}
std::array<int, 2> getEyePos(std::string LR)
{
	std::array eyePosition;
	return eyePosition;
}<|endoftext|>


<commit_before>// Copyright (C) 2012 Rhys Ulerich
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/** @file
 * Estimate the best AR(p) model given data on standard input.  Illustrates
 * \ref ar::autocorrelation, \ref ar::predictor,
 * and \ref ar::decorrelation_time.
 */

#include "ar.hpp"
#include "optionparser.h"

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <vector>

// Forward declarations for argument checking logic
struct Arg : public option::Arg
{
    static option::ArgStatus NonEmpty(const option::Option& opt, bool msg);
    static option::ArgStatus Numeric (const option::Option& opt, bool msg);
};

// Command line argument declarations for optionparser.h usage
enum OptionIndex { UNKNOWN, CRITERION, HELP, SUBMEAN, SIGNRHO };
const option::Descriptor usage[] = {
    {UNKNOWN, 0, "", "",      option::Arg::None,
     "Usage: arsel [OPTION]...\n"
     "Fit an optimal autoregressive model to data from standard input.\n"
     "\n"
     "Options:" },
    {0,0,"","",Arg::None,0}, // table break
    {CRITERION, 0,  "c",  "criterion",     Arg::NonEmpty,
     "  -c \t--criterion=ABBREV  \tUse the specified model order selection criterion" },
    {HELP,      0,  "h", "help",           Arg::None,
     "  -h \t--help        \tDisplay this help message and immediately exit" },
    {SUBMEAN,   0,  "m",  "subtract-mean", Arg::None,
     "  -m \t--subtract-mean  \tSubtract the sample mean from the incoming data" },
    {SIGNRHO,   0,  "r",  "signed-rho",    Arg::None,
     "  -r \t--signed-rho     \tUse signed autocorrelation values when computing T0" },
    {0,0,0,0,0,0}
};

int main(int argc, char *argv[])
{
    using namespace std;

    // TODO Add processing of files specified on the command line

    // Parse and process any command line arguments using optionparser.h
    string criterion   = "";
    bool subtract_mean = false;
    bool absolute_rho  = true;
    {
        option::Stats stats(usage, argc-(argc>0), argv+(argc>0));

        struct Guard // scoped_array or unique_ptr would add dependencies
        {
            option::Option *options;
            Guard(unsigned n) : options(new option::Option[n]) {}
            ~Guard() { delete[] options; }
        } g(stats.options_max + stats.buffer_max);

        option::Parser parse(usage, argc-(argc>0), argv+(argc>0),
                             g.options, g.options + stats.options_max);

        if (parse.error() || g.options[UNKNOWN]) {
            for (option::Option* o = g.options[UNKNOWN]; o; o = o->next()) {
                cerr << "Unknown option: " << o->name << "\n";
            }
            return EXIT_FAILURE;
        }

        if (g.options[HELP]) {
            printUsage(cout, usage);
            return EXIT_SUCCESS;
        }

        if (g.options[CRITERION])
            criterion = g.options[CRITERION].last()->arg;

        if (g.options[SUBMEAN])
            subtract_mean = true;

        if (g.options[SIGNRHO])
            absolute_rho = false;
    }

    // Look up desired model selection criterion using ar::best_model_function
    // best_model_function template parameters fit ar::burg_method usage below
    typedef ar::best_model_function<
            ar::Burg,size_t,vector<double> > best_model_function;
    const best_model_function::type best_model
            = best_model_function::lookup(criterion, subtract_mean);
    if (!best_model) {
        cerr << "Unknown model selection criterion: " << criterion << "\n";
        return EXIT_FAILURE;
    }

    // Use burg_method to estimate a hierarchy of AR models from input data
    double mean;
    size_t order = 512;
    vector<double> params, sigma2e, gain, autocor;
    params .reserve(order*(order + 1)/2);
    sigma2e.reserve(order + 1);
    gain   .reserve(order + 1);
    autocor.reserve(order + 1);
    const size_t N = ar::burg_method(istream_iterator<double>(cin),
                                     istream_iterator<double>(),
                                     mean,
                                     order,
                                     back_inserter(params),
                                     back_inserter(sigma2e),
                                     back_inserter(gain),
                                     back_inserter(autocor),
                                     subtract_mean,
                                     /* output hierarchy? */ true);

    // Keep only best model according to selected criterion
    best_model(N, params, sigma2e, gain, autocor);

    // Compute decorrelation time from the estimated autocorrelation model
    const double T0  = ar::decorrelation_time(N, ar::autocorrelation(
                params.begin(), params.end(), gain[0], autocor.begin()),
                absolute_rho);

    // Output details about the best model and derived information
    // Unbiased effective variance expression from [Trenberth1984]
    cout.precision(numeric_limits<double>::digits10 + 2);
    cout << showpos
         <<   "# N                   "   << N
         << "\n# AR(p)               "   << params.size()
         << "\n# Mean                "   << mean
         << "\n# \\sigma^2_\\epsilon   " << sigma2e[0]
         << "\n# Variance_effective  "   << (N*gain[0]*sigma2e[0]) / (N - T0)
         << "\n# N_effective         "   << N / T0
         << "\n# t_decorrelation     "   << T0
         << '\n';
    copy(params.begin(), params.end(), ostream_iterator<double>(cout,"\n"));
    cout.flush();

    return EXIT_SUCCESS;
}

// Argument checking logic suggested by optionparser.h example routines
option::ArgStatus Arg::NonEmpty(const option::Option& opt, bool msg)
{
    if (opt.arg != 0 && opt.arg[0] != 0) {
        return option::ARG_OK;
    }

    if (msg) {
        (std::cerr << "Option ").write(opt.name, opt.namelen)
                    << " requires a non-empty argument\n";
    }
    return option::ARG_ILLEGAL;
}

// Argument checking logic suggested by optionparser.h example routines
option::ArgStatus Arg::Numeric(const option::Option& opt, bool msg)
{
    char *endptr;
    if (opt.arg != 0 && strtol(opt.arg, &endptr, 10) && *endptr == 0) {
        return option::ARG_OK;
    }

    if (msg) {
        (std::cerr << "Option ").write(opt.name, opt.namelen)
                    << " requires a numeric argument\n";
    }
    return option::ARG_ILLEGAL;
}
<commit_msg>Add --order option to arsel<commit_after>// Copyright (C) 2012 Rhys Ulerich
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/** @file
 * Estimate the best AR(p) model given data on standard input.  Illustrates
 * \ref ar::autocorrelation, \ref ar::predictor,
 * and \ref ar::decorrelation_time.
 */

#include "ar.hpp"
#include "optionparser.h"

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <vector>

// Forward declarations for argument checking logic
struct Arg : public option::Arg
{
    static option::ArgStatus NonEmpty   (const option::Option& opt, bool msg);
    static option::ArgStatus NonNegative(const option::Option& opt, bool msg);
};

// Command line argument declarations for optionparser.h usage
enum OptionIndex { UNKNOWN, CRITERION, HELP, SUBMEAN, ORDER, SIGNRHO };
const option::Descriptor usage[] = {
    {UNKNOWN, 0, "", "",      option::Arg::None,
     "Usage: arsel [OPTION]...\n"
     "Fit an optimal autoregressive model to data from standard input.\n"
     "\n"
     "Options:" },
    {0,0,"","",Arg::None,0}, // table break
    {CRITERION, 0,  "c",  "criterion",     Arg::NonEmpty,
     "  -c \t--criterion=ABBREV  \tUse the specified model order selection criterion" },
    {HELP,      0,  "h", "help",           Arg::None,
     "  -h \t--help        \tDisplay this help message and immediately exit" },
    {SUBMEAN,   0,  "m",  "subtract-mean", Arg::None,
     "  -m \t--subtract-mean  \tSubtract the sample mean from the incoming data" },
    {ORDER,     0,  "o",  "order",         Arg::NonNegative,
     "  -o \t--order=MAXIMUM  \tConsider models no higher than the given order" },
    {SIGNRHO,   0,  "r",  "signed-rho",    Arg::None,
     "  -r \t--signed-rho     \tUse signed autocorrelation values when computing T0" },
    {0,0,0,0,0,0}
};

int main(int argc, char *argv[])
{
    using namespace std;

    // TODO Add processing of files specified on the command line

    // Parse and process any command line arguments using optionparser.h
    string criterion     = "";
    bool   subtract_mean = false;
    size_t order         = 512;
    bool   absolute_rho  = true;
    {
        option::Stats stats(usage, argc-(argc>0), argv+(argc>0));

        struct Guard // scoped_array or unique_ptr would add dependencies
        {
            option::Option *options;
            Guard(unsigned n) : options(new option::Option[n]) {}
            ~Guard() { delete[] options; }
        } g(stats.options_max + stats.buffer_max);

        option::Parser parse(usage, argc-(argc>0), argv+(argc>0),
                             g.options, g.options + stats.options_max);

        if (parse.error() || g.options[UNKNOWN]) {
            for (option::Option* o = g.options[UNKNOWN]; o; o = o->next()) {
                cerr << "Unknown option: " << o->name << "\n";
            }
            return EXIT_FAILURE;
        }

        if (g.options[HELP]) {
            printUsage(cout, usage);
            return EXIT_SUCCESS;
        }

        if (g.options[CRITERION])
            criterion = g.options[CRITERION].last()->arg;

        if (g.options[SUBMEAN])
            subtract_mean = true;

        if (g.options[ORDER])
            order = (size_t) strtol(g.options[ORDER].last()->arg, NULL, 10);

        if (g.options[SIGNRHO])
            absolute_rho = false;
    }

    // Look up desired model selection criterion using ar::best_model_function
    // best_model_function template parameters fit ar::burg_method usage below
    typedef ar::best_model_function<
            ar::Burg,size_t,vector<double> > best_model_function;
    const best_model_function::type best_model
            = best_model_function::lookup(criterion, subtract_mean);
    if (!best_model) {
        cerr << "Unknown model selection criterion: " << criterion << "\n";
        return EXIT_FAILURE;
    }

    // Use burg_method to estimate a hierarchy of AR models from input data
    double mean;
    vector<double> params, sigma2e, gain, autocor;
    params .reserve(order*(order + 1)/2);
    sigma2e.reserve(order + 1);
    gain   .reserve(order + 1);
    autocor.reserve(order + 1);
    const size_t N = ar::burg_method(istream_iterator<double>(cin),
                                     istream_iterator<double>(),
                                     mean,
                                     order,
                                     back_inserter(params),
                                     back_inserter(sigma2e),
                                     back_inserter(gain),
                                     back_inserter(autocor),
                                     subtract_mean,
                                     /* output hierarchy? */ true);

    // Keep only best model according to selected criterion
    best_model(N, params, sigma2e, gain, autocor);

    // Compute decorrelation time from the estimated autocorrelation model
    const double T0  = ar::decorrelation_time(N, ar::autocorrelation(
                params.begin(), params.end(), gain[0], autocor.begin()),
                absolute_rho);

    // Output details about the best model and derived information
    // Unbiased effective variance expression from [Trenberth1984]
    cout.precision(numeric_limits<double>::digits10 + 2);
    cout << showpos
         <<   "# N                   "   << N
         << "\n# AR(p)               "   << params.size()
         << "\n# Mean                "   << mean
         << "\n# \\sigma^2_\\epsilon   " << sigma2e[0]
         << "\n# Variance_effective  "   << (N*gain[0]*sigma2e[0]) / (N - T0)
         << "\n# N_effective         "   << N / T0
         << "\n# t_decorrelation     "   << T0
         << '\n';
    copy(params.begin(), params.end(), ostream_iterator<double>(cout,"\n"));
    cout.flush();

    return EXIT_SUCCESS;
}

// Argument checking logic suggested by optionparser.h example routines
option::ArgStatus Arg::NonEmpty(const option::Option& opt, bool msg)
{
    if (opt.arg != 0 && opt.arg[0] != 0) {
        return option::ARG_OK;
    }

    if (msg) {
        (std::cerr << "Option ").write(opt.name, opt.namelen)
                    << " requires a non-empty argument\n";
    }
    return option::ARG_ILLEGAL;
}

// Argument checking logic based upon optionparser.h example routines
option::ArgStatus Arg::NonNegative(const option::Option& opt, bool msg)
{
    char *p = 0;
    if (opt.arg) {
        double v = strtol(opt.arg, &p, 10);
        if (p != opt.arg && !*p && v >= 0) {
            return option::ARG_OK;
        }
    }

    if (msg) {
        (std::cerr << "Option ").write(opt.name, opt.namelen)
                    << " requires a nonnegative numeric argument\n";
    }
    return option::ARG_ILLEGAL;
}
<|endoftext|>