summaryrefslogtreecommitdiffstats
path: root/src/cmd_socket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd_socket.cpp')
-rw-r--r--src/cmd_socket.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/cmd_socket.cpp b/src/cmd_socket.cpp
new file mode 100644
index 0000000..3f38999
--- /dev/null
+++ b/src/cmd_socket.cpp
@@ -0,0 +1,200 @@
+/*
+ Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include "cmd_socket.h"
+#include "log.h"
+#include "sys_settings.h"
+#include "userintf.h"
+#include "util.h"
+#include "audits/memman.h"
+#include "sockets/socket.h"
+
+namespace cmdsocket {
+
+/** Command opcodes */
+enum t_cmd_code {
+ CMD_CALL, /**< Call */
+ CMD_CLI, /**< Any CLI command */
+ CMD_SHOW, /**< Show Twinkle */
+ CMD_HIDE /**< Hide Twinkle */
+};
+
+string cmd_code2str(t_cmd_code opcode) {
+ switch (opcode) {
+ case CMD_CALL:
+ return "CALL";
+ case CMD_CLI:
+ return "CLI";
+ case CMD_SHOW:
+ return "SHOW";
+ case CMD_HIDE:
+ return "HIDE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+void exec_cmd(t_socket_local &sock_client) {
+ t_cmd_code opcode;
+ bool immediate;
+ int len;
+ string log_msg;
+
+ try {
+ if (sock_client.read(&opcode, sizeof(opcode)) != sizeof(opcode)) {
+ log_file->write_report("Failed to read opcode from socket.",
+ "cmdsocket::exec_cmd", LOG_NORMAL, LOG_WARNING);
+ return;
+ }
+
+ if (sock_client.read(&immediate, sizeof(immediate)) != sizeof(immediate)) {
+ log_file->write_report("Failed to read immediate mode from socket.",
+ "cmdsocket::exec_cmd", LOG_NORMAL, LOG_WARNING);
+ return;
+ }
+
+ if (sock_client.read(&len, sizeof(len)) != sizeof(len)) {
+ log_file->write_report("Failed to read length from socket.",
+ "cmdsocket::exec_cmd", LOG_NORMAL, LOG_WARNING);
+ return;
+ }
+
+ char args[len];
+
+ if (sock_client.read(args, len) != len) {
+ log_file->write_report("Failed to read arguments from socket.",
+ "cmdsocket::exec_cmd", LOG_NORMAL, LOG_WARNING);
+ return;
+ }
+
+ log_file->write_header("cmdsocket::exec_cmd", LOG_NORMAL, LOG_DEBUG);
+ log_file->write_raw("External command received:\n");
+ log_file->write_raw("Opcode: ");
+ log_file->write_raw(cmd_code2str(opcode));
+ log_file->write_raw("\nImmediate: ");
+ log_file->write_raw(bool2yesno(immediate));
+ log_file->write_raw("\nArguments: ");
+ log_file->write_raw(args);
+ log_file->write_endl();
+ log_file->write_footer();
+
+ switch (opcode) {
+ case CMD_CALL:
+ ui->cmd_call(args, immediate);
+ break;
+ case CMD_CLI:
+ ui->cmd_cli(args, immediate);
+ break;
+ case CMD_SHOW:
+ ui->cmd_show();
+ break;
+ case CMD_HIDE:
+ ui->cmd_hide();
+ break;
+ default:
+ // Discard unknown commands
+ log_file->write_header("cmdsocket::exec_cmd", LOG_NORMAL, LOG_WARNING);
+ log_file->write_raw("Unknown external command received:\n");
+ log_file->write_raw("Opcode: ");
+ log_file->write_raw(cmd_code2str(opcode));
+ log_file->write_raw("\nImmediate: ");
+ log_file->write_raw(bool2yesno(immediate));
+ log_file->write_raw("\nArguments: ");
+ log_file->write_raw(args);
+ log_file->write_endl();
+ log_file->write_footer();
+ break;
+ }
+ }
+ catch (int e) {
+ log_msg = "Failed to read from socket.\n";
+ log_msg += get_error_str(e);
+ log_msg += "\n";
+ log_file->write_report(log_msg, "cmdsocket::exec_cmd", LOG_NORMAL, LOG_WARNING);
+ }
+}
+
+void *listen_cmd(void *arg) {
+ t_socket_local *sock_cmd = (t_socket_local *)arg;
+ string log_msg;
+
+ while (true) {
+ try {
+ int fd = sock_cmd->accept();
+ t_socket_local sock_client(fd);
+ exec_cmd(sock_client);
+ }
+ catch (int e) {
+ log_msg = "Accept failed on socket.\n";
+ log_msg += get_error_str(e);
+ log_msg += "\n";
+ log_file->write_report(log_msg, "cmdsocket::listen_cmd", LOG_NORMAL,
+ LOG_WARNING);
+ return NULL;
+ }
+ }
+}
+
+void write_cmd_to_socket(t_cmd_code opcode, bool immediate, const string &args) {
+ string name = sys_config->get_dir_user();
+ name += '/';
+ name += CMD_SOCKNAME;
+
+ try {
+ t_socket_local sock_cmd;
+ sock_cmd.connect(name);
+ sock_cmd.write(&opcode, sizeof(opcode));
+ sock_cmd.write(&immediate, sizeof(immediate));
+ int len = args.size() + 1;
+ sock_cmd.write(&len, sizeof(len));
+ char *buf = strdup(args.c_str());
+ MEMMAN_NEW(buf);
+ sock_cmd.write(buf, len);
+ MEMMAN_DELETE(buf);
+ free(buf);
+ }
+ catch (int e) {
+ // This function will be called from Twinkle when it
+ // notices another Twinkle is already running. In that
+ // case this process does not have a log file. So write
+ // errors to stderr
+ cerr << "Failed to send " << cmd_code2str(opcode) << " command to " << name << endl;
+ cerr << get_error_str(e) << endl;
+ }
+}
+
+void cmd_call(const string &destination, bool immediate) {
+ write_cmd_to_socket(CMD_CALL, immediate, destination);
+}
+
+void cmd_cli(const string &cli_command, bool immediate) {
+ write_cmd_to_socket(CMD_CLI, immediate, cli_command);
+}
+
+void cmd_show(void) {
+ write_cmd_to_socket(CMD_SHOW, true, "");
+}
+
+void cmd_hide(void) {
+ write_cmd_to_socket(CMD_HIDE, true, "");
+}
+
+}