147 lines
4.1 KiB
C++
147 lines
4.1 KiB
C++
#include <argp.h>
|
|
#include <chrono>
|
|
#include <csignal>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <regex>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <regex>
|
|
|
|
#include <gloox/gloox.h>
|
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
#include <cfg_cmdline.h>
|
|
#include <cfg_file.h>
|
|
#include <chat.h>
|
|
#include <config.h>
|
|
#include <muc.h>
|
|
#include <util.h>
|
|
#include <xmpp.h>
|
|
|
|
using namespace std;
|
|
using namespace gloox;
|
|
|
|
shared_ptr<SmplXmppHandlerBase> global_handler = 0;
|
|
|
|
bool parse_input_line(string line, MsgPrototype& msg) {
|
|
static const regex re_prefix("^([^\\n\\t ]*)[\\t ](.*)$");
|
|
|
|
msg = {"", ""};
|
|
if (!opts.cfg.mucMode && opts.cfg.focusedUsers.empty() && !opts.cfg.titForTatMode) {
|
|
smatch m;
|
|
if (!regex_match(line, m, re_prefix)) {
|
|
return false;
|
|
}
|
|
|
|
msg.jid = m[1];
|
|
msg.body = newlinesDecode(m[2]);
|
|
|
|
if (msg.jid.empty()) {
|
|
return false;
|
|
}
|
|
} else {
|
|
msg.body = newlinesDecode(line);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void send_msg(const MsgPrototype& msg) {
|
|
if (opts.cfg.mucMode) {
|
|
spdlog::trace("sending muc msg '{}'", msg.body);
|
|
global_handler->enqueueMsg("", msg.body);
|
|
} else if (!opts.cfg.focusedUsers.empty()) {
|
|
spdlog::trace("sending msg to all focused users: '{}'", msg.body);
|
|
for (const auto user : opts.cfg.focusedUsers) {
|
|
global_handler->enqueueMsg(user.full(), msg.body);
|
|
}
|
|
} else {
|
|
spdlog::trace("sending to '{}' the msg '{}'", msg.jid, msg.body);
|
|
global_handler->enqueueMsg(msg.jid, msg.body);
|
|
}
|
|
}
|
|
|
|
void input_cycle() {
|
|
spdlog::debug("ready to read from stdin");
|
|
string line;
|
|
MsgPrototype msg;
|
|
|
|
while(getline(cin, line)) {
|
|
// decoding
|
|
if (!parse_input_line(line, msg)) {
|
|
spdlog::warn("parsing line failed. expected '<jid><tab or whitespace><encoded msg>'");
|
|
continue;
|
|
}
|
|
|
|
// handling
|
|
send_msg(msg);
|
|
}
|
|
|
|
spdlog::info("read EOF from stdin, stopping");
|
|
global_handler->stop();
|
|
}
|
|
|
|
void signal_handler(int signal) {
|
|
static chrono::time_point<chrono::steady_clock> last_signal = chrono::steady_clock::now() - chrono::hours(1);
|
|
|
|
if (0 != global_handler) {
|
|
spdlog::info("received signal {}, stopping gracefully", signal);
|
|
spdlog::info("send another signal within 1 second to kill forcefully");
|
|
|
|
global_handler->stop();
|
|
}
|
|
|
|
auto since_last_signal = chrono::steady_clock::now() - last_signal;
|
|
if (since_last_signal < chrono::seconds(1)) {
|
|
spdlog::critical("received second signal within 1 second, quitting forcefully");
|
|
exit(1);
|
|
}
|
|
|
|
last_signal = chrono::steady_clock::now();
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
initSpdlog();
|
|
|
|
struct argp argp = {options, parse_opt, "", "simple XMPP command line client\vInput/Output format:\nuser1@host.tld message 1\nuser2@host.tld message 2\n\nInput/Output format when using --muc or --focus:\nmessage 1\nmessage 2\n\nEach line holds a single message.\nBackslashes (\\) are converted to \\\\, newlines to \\n.\nTo encode/decode messages in scripts use smplxmpp-nl.\n\nBuilt by Rolf Pfeffertal."};
|
|
|
|
int argp_result = argp_parse(&argp, argc, argv, 0, 0, 0);
|
|
|
|
// enforce load cfg at least once
|
|
load_cfg_files_once();
|
|
|
|
if (argp_result != 0) {
|
|
return argp_result;
|
|
}
|
|
|
|
if (opts.cfg.mucMode) {
|
|
global_handler = make_shared<SmplXmppHandlerMuc>(JID(opts.jid), opts.pass, opts.cfg);
|
|
} else {
|
|
global_handler = make_shared<SmplXmppHandlerChat>(JID(opts.jid), opts.pass, opts.cfg);
|
|
}
|
|
|
|
// install message handler
|
|
signal(SIGINT, signal_handler);
|
|
signal(SIGTERM, signal_handler);
|
|
|
|
if (opts.cfg.enableInput) {
|
|
// branch to input cycle
|
|
spdlog::trace("launching stdin handler");
|
|
thread input_thread(input_cycle);
|
|
input_thread.detach();
|
|
} else {
|
|
spdlog::trace("didn't enable input handling");
|
|
}
|
|
|
|
// enter blocking state
|
|
spdlog::info("init done, setting up connection...");
|
|
global_handler->start();
|
|
|
|
return 0;
|
|
}
|