summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2011-01-01 21:04:17 +0100
committerJon Bergli Heier <snakebite@jvnv.net>2011-01-01 21:04:17 +0100
commit14500d43760661ffc3ffb67d929088c27fe46c64 (patch)
tree75d9471a61b00eb56b7ee75b3a785a392edb0dad
parent0e7f2cef26bde782a5758b5e9a3dfe20f745df8f (diff)
Implemented a simple 'ls' command for the telnet server.
-rw-r--r--commands.cpp45
-rw-r--r--commands.h24
-rw-r--r--main.cpp2
-rw-r--r--music.cpp8
-rw-r--r--music.h1
-rw-r--r--telnet_connection.cpp66
-rw-r--r--telnet_connection.h4
7 files changed, 149 insertions, 1 deletions
diff --git a/commands.cpp b/commands.cpp
new file mode 100644
index 0000000..dfeeebb
--- /dev/null
+++ b/commands.cpp
@@ -0,0 +1,45 @@
+#include "commands.h"
+#include "music.h"
+
+#include <boost/cast.hpp>
+
+#include <iostream>
+
+static std::vector<std::string> ls(const std::vector<std::string>& args) {
+ if(args.size() != 2) {
+ throw commands::CommandException("usage: ls DIR");
+ }
+
+ MusicListing::p ml = music::get(args[1]);
+ if(!ml || !fs::is_directory(ml->path)) {
+ throw commands::CommandException("no such directory");
+ }
+ std::vector<std::string> result;
+ MusicDirectory *dir = boost::polymorphic_downcast<MusicDirectory*>(&(*ml));
+ for(MusicDirectory::PathListings::iterator it = dir->directories.begin(); it != dir->directories.end(); it++) {
+ std::string rel_path = it->string().substr(music::root_directory.string().size());
+ result.push_back(rel_path);
+ }
+ for(MusicDirectory::PathListings::iterator it = dir->tracks.begin(); it != dir->tracks.end(); it++) {
+ std::string rel_path = it->string().substr(music::root_directory.string().size());
+ result.push_back(rel_path);
+ }
+
+ return result;
+}
+
+std::map<std::string, commands::Handler> commands::handlers;
+
+void commands::init() {
+ handlers["ls"] = ls;
+}
+
+std::vector<std::string> commands::execute(const std::vector<std::string>& args) {
+ assert(args.size());
+ Handler h = commands::handlers[args[0]];
+ if(!h) {
+ throw CommandException("unknown command");
+ }
+
+ return h(args);
+}
diff --git a/commands.h b/commands.h
new file mode 100644
index 0000000..bc4092f
--- /dev/null
+++ b/commands.h
@@ -0,0 +1,24 @@
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+#include <boost/function.hpp>
+
+#include <string>
+#include <vector>
+#include <map>
+#include <stdexcept>
+
+namespace commands {
+ typedef boost::function<std::vector<std::string> (const std::vector<std::string>&)> Handler;
+ extern std::map<std::string, commands::Handler> handlers;
+
+ class CommandException : public std::runtime_error {
+ public:
+ CommandException(const char *s) : std::runtime_error(s) {};
+ };
+
+ void init();
+ std::vector<std::string> execute(const std::vector<std::string>& args);
+};
+
+#endif
diff --git a/main.cpp b/main.cpp
index ccca2ad..f9f2d8e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4,6 +4,7 @@
#include "encoder.h"
#include "httpd.h"
#include "telnetd.h"
+#include "commands.h"
#include <iostream>
#include <vector>
@@ -16,6 +17,7 @@ int main(int argc, char **argv) {
music::init(config::vm["audist.music_root"].as<std::string>());
decoder::init();
encoder::init();
+ commands::init();
boost::asio::io_service io_service;
diff --git a/music.cpp b/music.cpp
index 5292e66..295f5e4 100644
--- a/music.cpp
+++ b/music.cpp
@@ -7,6 +7,8 @@
#include <boost/format.hpp>
#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem/fstream.hpp>
#include <soci/soci.h>
@@ -49,6 +51,12 @@ MusicListing::p music::get(const std::vector<std::string>& path) {
return MusicListing::p();
}
+MusicListing::p music::get(const std::string& path) {
+ std::vector<std::string> path_vector;
+ boost::algorithm::split(path_vector, path, boost::algorithm::is_any_of("/\\"));
+ return get(path_vector);
+}
+
std::vector<MusicListing::p> music::find_artist(const std::string artist) {
soci::session sql(config::vm["audist.database"].as<std::string>());
diff --git a/music.h b/music.h
index fe3ca4a..0c4e421 100644
--- a/music.h
+++ b/music.h
@@ -37,6 +37,7 @@ namespace music {
extern fs::path root_directory;
void init(std::string root);
MusicListing::p get(const std::vector<std::string>& path);
+ MusicListing::p get(const std::string& path);
std::vector<MusicListing::p> find_artist(const std::string artist);
};
diff --git a/telnet_connection.cpp b/telnet_connection.cpp
index e2ea96f..457d1ba 100644
--- a/telnet_connection.cpp
+++ b/telnet_connection.cpp
@@ -1,12 +1,76 @@
#include "telnet_connection.h"
+#include "commands.h"
#include <boost/bind.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/format.hpp>
+
+#include <iostream>
telnet::Connection::Connection(boost::asio::io_service& io_service) : socket(io_service) {
}
void telnet::Connection::handle_read(const boost::system::error_code& error, size_t bytes_transferred) {
- boost::asio::write(socket, buf);
+ if(error) {
+ return;
+ }
+
+ std::string line;
+ std::istream is(&buf);
+ std::getline(is, line);
+ boost::trim(line);
+
+ if(line == "exit") {
+ return;
+ }
+
+ std::vector<std::string> args = parse_args(line);
+ // no arguments, i.e. empty line
+ if(!args.size()) {
+ start();
+ return;
+ }
+
+ std::vector<std::string> r;
+ try {
+ r = commands::execute(args);
+ } catch(commands::CommandException& ce) {
+ std::string s(ce.what());
+ s += '\n';
+ boost::asio::write(socket, boost::asio::buffer(s));
+ start();
+ return;
+ }
+
+ for(std::vector<std::string>::iterator it = r.begin(); it != r.end(); it++) {
+ boost::asio::write(socket, boost::asio::buffer(*it + "\n"));
+ }
+
+ start();
+}
+
+std::vector<std::string> telnet::Connection::parse_args(std::string& line) {
+ std::string::const_iterator begin = line.begin();
+ std::string::const_iterator end = line.end();
+
+ boost::regex re("(\")?((?(1)[^\"]|[^ ])+)(?(1)\")");
+ boost::match_results<std::string::const_iterator> what;
+ boost::match_flag_type flags = boost::match_default;
+
+ std::vector<std::string> args;
+
+ while(boost::regex_search(begin, end, what, re, flags)) {
+ std::string s = std::string(what[2].first, what[2].second);
+ boost::algorithm::trim(s);
+ // avoid empty strings when parsing multi-word arguments (a "b c")
+ if(s.size()) {
+ args.push_back(s);
+ }
+ begin = what[0].second;
+ }
+
+ return args;
}
void telnet::Connection::start() {
diff --git a/telnet_connection.h b/telnet_connection.h
index 8ea3cad..68d652e 100644
--- a/telnet_connection.h
+++ b/telnet_connection.h
@@ -4,6 +4,9 @@
#include <boost/asio.hpp>
#include <boost/enable_shared_from_this.hpp>
+#include <vector>
+#include <string>
+
using boost::asio::ip::tcp;
namespace telnet {
@@ -13,6 +16,7 @@ namespace telnet {
private:
Connection(boost::asio::io_service& io_service);
void handle_read(const boost::system::error_code& error, size_t bytes_transferred);
+ std::vector<std::string> parse_args(std::string& line);
tcp::socket socket;
boost::asio::streambuf buf;