main.cpp 2.79 KB
Newer Older
1
#include <xmpp/xmpp_component.hpp>
2 3
#include <network/poller.hpp>
#include <config/config.hpp>
louiz’'s avatar
louiz’ committed
4
#include <logger/logger.hpp>
5

6
#include <iostream>
7
#include <memory>
louiz’'s avatar
louiz’ committed
8 9 10 11 12 13 14 15 16
#include <atomic>

#include <signal.h>

// A flag set by the SIGINT signal handler.
volatile std::atomic<bool> stop(false);
// A flag indicating that we are wanting to exit the process. i.e: if this
// flag is set and all connections are closed, we can exit properly.
static bool exiting = false;
17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/**
 * Provide an helpful message to help the user write a minimal working
 * configuration file.
 */
int config_help(const std::string& missing_option)
{
  if (!missing_option.empty())
    std::cerr << "Error: empty value for option " << missing_option << "." << std::endl;
  std::cerr <<
    "Please provide a configuration file filled like this:\n\n"
    "hostname=irc.example.com\npassword=S3CR3T"
            << std::endl;
  return 1;
}

louiz’'s avatar
louiz’ committed
33 34 35 36 37
static void sigint_handler(int, siginfo_t*, void*)
{
  stop = true;
}

38
int main(int ac, char** av)
louiz’'s avatar
louiz’ committed
39
{
40 41 42
  if (ac > 1)
    Config::filename = av[1];
  Config::file_must_exist = true;
43
  std::cerr << "Using configuration file: " << Config::filename << std::endl;
44 45 46 47 48 49

  std::string password;
  try { // The file must exist
    password = Config::get("password", "");
  }
  catch (const std::ios::failure& e) {
50
    return config_help("");
51
  }
52
  const std::string hostname = Config::get("hostname", "");
53
  if (password.empty())
54
    return config_help("password");
55 56
  if (hostname.empty())
    return config_help("hostname");
57
  std::shared_ptr<XmppComponent> xmpp_component =
58
    std::make_shared<XmppComponent>(hostname, password);
59 60

  Poller p;
61
  p.add_socket_handler(xmpp_component);
louiz’'s avatar
louiz’ committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  if (!xmpp_component->start())
  {
    log_info("Exiting");
    return -1;
  }

  // Install the signals used to exit the process cleanly, or reload the
  // config
  sigset_t mask;
  sigemptyset(&mask);
  struct sigaction on_sig;
  on_sig.sa_sigaction = &sigint_handler;
  on_sig.sa_mask = mask;
  // we want to catch that signal only once.
  // Sending SIGINT again will "force" an exit
  on_sig.sa_flags = SA_RESETHAND;
  sigaction(SIGINT, &on_sig, nullptr);
  sigaction(SIGTERM, &on_sig, nullptr);

  const std::chrono::milliseconds timeout(-1);
  while (p.poll(timeout) != -1 || !exiting)
  {
louiz’'s avatar
louiz’ committed
84 85 86
    // Check for empty irc_clients (not connected, or with no joined
    // channel) and remove them
    xmpp_component->clean();
louiz’'s avatar
louiz’ committed
87 88 89 90 91 92 93 94 95 96 97 98 99
    if (stop)
    {
      log_info("Signal received, exiting...");
      exiting = true;
      stop = false;
      xmpp_component->shutdown();
    }
    // If the only existing connection is the one to the XMPP component:
    // close the XMPP stream.
    if (exiting && p.size() == 1 && xmpp_component->is_document_open())
      xmpp_component->close_document();
  }
  log_info("All connection cleanely closed, have a nice day.");
louiz’'s avatar
louiz’ committed
100 101
  return 0;
}