/* nutclient.cpp - nutclient C++ library implementation Copyright (C) 2012 Emilien Kia 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 "nutclient.h" #include #include #include #include /* Windows/Linux Socket compatibility layer: */ /* Thanks to Benjamin Roux (http://broux.developpez.com/articles/c/sockets/) */ #ifdef WIN32 # include #else # include # include # include # include # include /* close */ # include /* gethostbyname */ # include # define INVALID_SOCKET -1 # define SOCKET_ERROR -1 # define closesocket(s) close(s) typedef int SOCKET; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; typedef struct in_addr IN_ADDR; #endif /* WIN32 */ /* End of Windows/Linux Socket compatibility layer: */ /* Include nut common utility functions or define simple ones if not */ #ifdef HAVE_NUTCOMMON #include "common.h" #else /* HAVE_NUTCOMMON */ #include #include static inline void *xmalloc(size_t size){return malloc(size);} static inline void *xcalloc(size_t number, size_t size){return calloc(number, size);} static inline void *xrealloc(void *ptr, size_t size){return realloc(ptr, size);} static inline char *xstrdup(const char *string){return strdup(string);} #endif /* HAVE_NUTCOMMON */ namespace nut { SystemException::SystemException(): NutException(err()) { } std::string SystemException::err() { if(errno==0) return "Undefined system error"; else { std::stringstream str; str << "System error " << errno << ": " << strerror(errno); return str.str(); } } namespace internal { /** * Internal socket wrapper. * Provides only client socket functions. * * Implemented as separate internal class to easily hide plateform specificities. */ class Socket { public: Socket(); void connect(const std::string& host, int port)throw(nut::IOException); void disconnect(); bool isConnected()const; void setTimeout(long timeout); bool hasTimeout()const{return _tv.tv_sec>=0;} size_t read(void* buf, size_t sz)throw(nut::IOException); size_t write(const void* buf, size_t sz)throw(nut::IOException); std::string read()throw(nut::IOException); void write(const std::string& str)throw(nut::IOException); private: SOCKET _sock; struct timeval _tv; std::string _buffer; /* Received buffer, string because data should be text only. */ }; Socket::Socket(): _sock(INVALID_SOCKET), _tv() { _tv.tv_sec = -1; _tv.tv_usec = 0; } void Socket::setTimeout(long timeout) { _tv.tv_sec = timeout; } void Socket::connect(const std::string& host, int port)throw(nut::IOException) { int sock_fd; struct addrinfo hints, *res, *ai; char sport[NI_MAXSERV]; int v; fd_set wfds; int error; socklen_t error_size; long fd_flags; _sock = -1; if (host.empty()) { throw nut::UnknownHostException(); } snprintf(sport, sizeof(sport), "%hu", (unsigned short int)port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; while ((v = getaddrinfo(host.c_str(), sport, &hints, &res)) != 0) { switch (v) { case EAI_AGAIN: continue; case EAI_NONAME: throw nut::UnknownHostException(); case EAI_SYSTEM: throw nut::SystemException(); case EAI_MEMORY: throw nut::NutException("Out of memory"); default: throw nut::NutException("Unknown error"); } } for (ai = res; ai != NULL; ai = ai->ai_next) { sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock_fd < 0) { switch (errno) { case EAFNOSUPPORT: case EINVAL: break; default: throw nut::SystemException(); } continue; } /* non blocking connect */ if(hasTimeout()) { fd_flags = fcntl(sock_fd, F_GETFL); fd_flags |= O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); } while ((v = ::connect(sock_fd, ai->ai_addr, ai->ai_addrlen)) < 0) { if(errno == EINPROGRESS) { FD_ZERO(&wfds); FD_SET(sock_fd, &wfds); select(sock_fd+1,NULL,&wfds,NULL, hasTimeout()?&_tv:NULL); if (FD_ISSET(sock_fd, &wfds)) { error_size = sizeof(error); getsockopt(sock_fd,SOL_SOCKET,SO_ERROR, &error,&error_size); if( error == 0) { /* connect successful */ v = 0; break; } errno = error; } else { /* Timeout */ v = -1; break; } } switch (errno) { case EAFNOSUPPORT: break; case EINTR: case EAGAIN: continue; default: // ups->upserror = UPSCLI_ERR_CONNFAILURE; // ups->syserrno = errno; break; } break; } if (v < 0) { close(sock_fd); continue; } /* switch back to blocking operation */ if(hasTimeout()) { fd_flags = fcntl(sock_fd, F_GETFL); fd_flags &= ~O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); } _sock = sock_fd; // ups->upserror = 0; // ups->syserrno = 0; break; } freeaddrinfo(res); if (_sock < 0) { throw nut::IOException("Cannot connect to host"); } #ifdef OLD struct hostent *hostinfo = NULL; SOCKADDR_IN sin = { 0 }; hostinfo = ::gethostbyname(host.c_str()); if(hostinfo == NULL) /* Host doesnt exist */ { throw nut::UnknownHostException(); } // Create socket _sock = ::socket(PF_INET, SOCK_STREAM, 0); if(_sock == INVALID_SOCKET) { throw nut::IOException("Cannot create socket"); } // Connect sin.sin_addr = *(IN_ADDR *) hostinfo->h_addr; sin.sin_port = htons(port); sin.sin_family = AF_INET; if(::connect(_sock,(SOCKADDR *) &sin, sizeof(SOCKADDR)) == SOCKET_ERROR) { _sock = INVALID_SOCKET; throw nut::IOException("Cannot connect to host"); } #endif // OLD } void Socket::disconnect() { if(_sock != INVALID_SOCKET) { ::closesocket(_sock); _sock = INVALID_SOCKET; } _buffer.clear(); } bool Socket::isConnected()const { return _sock!=INVALID_SOCKET; } size_t Socket::read(void* buf, size_t sz)throw(nut::IOException) { if(!isConnected()) { throw nut::NotConnectedException(); } if(_tv.tv_sec>=0) { fd_set fds; FD_ZERO(&fds); FD_SET(_sock, &fds); int ret = select(_sock+1, &fds, NULL, NULL, &_tv); if (ret < 1) { throw nut::TimeoutException(); } } ssize_t res = ::read(_sock, buf, sz); if(res==-1) { disconnect(); throw nut::IOException("Error while reading on socket"); } return (size_t) res; } size_t Socket::write(const void* buf, size_t sz)throw(nut::IOException) { if(!isConnected()) { throw nut::NotConnectedException(); } if(_tv.tv_sec>=0) { fd_set fds; FD_ZERO(&fds); FD_SET(_sock, &fds); int ret = select(_sock+1, NULL, &fds, NULL, &_tv); if (ret < 1) { throw nut::TimeoutException(); } } ssize_t res = ::write(_sock, buf, sz); if(res==-1) { disconnect(); throw nut::IOException("Error while writing on socket"); } return (size_t) res; } std::string Socket::read()throw(nut::IOException) { std::string res; char buff[256]; while(true) { // Look at already read data in _buffer if(!_buffer.empty()) { size_t idx = _buffer.find('\n'); if(idx!=std::string::npos) { res += _buffer.substr(0, idx); _buffer.erase(0, idx+1); return res; } res += _buffer; } // Read new buffer size_t sz = read(&buff, 256); if(sz==0) { disconnect(); throw nut::IOException("Server closed connection unexpectedly"); } _buffer.assign(buff, sz); } } void Socket::write(const std::string& str)throw(nut::IOException) { // write(str.c_str(), str.size()); // write("\n", 1); std::string buff = str + "\n"; write(buff.c_str(), buff.size()); } }/* namespace internal */ /* * * Client implementation * */ Client::Client() { } Client::~Client() { } bool Client::hasDevice(const std::string& dev)throw(NutException) { std::set devs = getDeviceNames(); return devs.find(dev) != devs.end(); } Device Client::getDevice(const std::string& name)throw(NutException) { if(hasDevice(name)) return Device(this, name); else return Device(NULL, ""); } std::set Client::getDevices()throw(NutException) { std::set res; std::set devs = getDeviceNames(); for(std::set::iterator it=devs.begin(); it!=devs.end(); ++it) { res.insert(Device(this, *it)); } return res; } bool Client::hasDeviceVariable(const std::string& dev, const std::string& name)throw(NutException) { std::set names = getDeviceVariableNames(dev); return names.find(name) != names.end(); } std::map > Client::getDeviceVariableValues(const std::string& dev)throw(NutException) { std::map > res; std::set names = getDeviceVariableNames(dev); for(std::set::iterator it=names.begin(); it!=names.end(); ++it) { const std::string& name = *it; res[name] = getDeviceVariableValue(dev, name); } return res; } bool Client::hasDeviceCommand(const std::string& dev, const std::string& name)throw(NutException) { std::set names = getDeviceCommandNames(dev); return names.find(name) != names.end(); } /* * * TCP Client implementation * */ TcpClient::TcpClient(): Client(), _host("localhost"), _port(3493), _socket(new internal::Socket) { // Do not connect now } TcpClient::TcpClient(const std::string& host, int port)throw(IOException): Client(), _socket(new internal::Socket) { connect(host, port); } TcpClient::~TcpClient() { delete _socket; } void TcpClient::connect(const std::string& host, int port)throw(IOException) { _host = host; _port = port; connect(); } void TcpClient::connect()throw(nut::IOException) { _socket->connect(_host, _port); } std::string TcpClient::getHost()const { return _host; } int TcpClient::getPort()const { return _port; } bool TcpClient::isConnected()const { return _socket->isConnected(); } void TcpClient::disconnect() { _socket->disconnect(); } void TcpClient::setTimeout(long timeout) { _timeout = timeout; } long TcpClient::getTimeout()const { return _timeout; } void TcpClient::authenticate(const std::string& user, const std::string& passwd) throw(NutException) { detectError(sendQuery("USERNAME " + user)); detectError(sendQuery("PASSWORD " + passwd)); } void TcpClient::logout()throw(NutException) { detectError(sendQuery("LOGOUT")); _socket->disconnect(); } Device TcpClient::getDevice(const std::string& name)throw(NutException) { try { get("UPSDESC", name); } catch(NutException& ex) { if(ex.str()=="UNKNOWN-UPS") return Device(NULL, ""); else throw; } return Device(this, name); } std::set TcpClient::getDeviceNames()throw(NutException) { std::set res; std::vector > devs = list("UPS"); for(std::vector >::iterator it=devs.begin(); it!=devs.end(); ++it) { std::string id = (*it)[0]; if(!id.empty()) res.insert(id); } return res; } std::string TcpClient::getDeviceDescription(const std::string& name)throw(NutException) { return get("UPSDESC", name)[0]; } std::set TcpClient::getDeviceVariableNames(const std::string& dev)throw(NutException) { std::set set; std::vector > res = list("VAR", dev); for(size_t n=0; n TcpClient::getDeviceRWVariableNames(const std::string& dev)throw(NutException) { std::set set; std::vector > res = list("RW", dev); for(size_t n=0; n TcpClient::getDeviceVariableValue(const std::string& dev, const std::string& name)throw(NutException) { return get("VAR", dev + " " + name); } std::map > TcpClient::getDeviceVariableValues(const std::string& dev)throw(NutException) { std::map > map; std::vector > res = list("VAR", dev); for(size_t n=0; n& vals = res[n]; std::string var = vals[0]; vals.erase(vals.begin()); map[var] = vals; } return map; } void TcpClient::setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value)throw(NutException) { std::string query = "SET VAR " + dev + " " + name + " " + escape(value); detectError(sendQuery(query)); } void TcpClient::setDeviceVariable(const std::string& dev, const std::string& name, const std::vector& values)throw(NutException) { std::string query = "SET VAR " + dev + " " + name; for(size_t n=0; n TcpClient::getDeviceCommandNames(const std::string& dev)throw(NutException) { std::set cmds; std::vector > res = list("CMD", dev); for(size_t n=0; n TcpClient::get (const std::string& subcmd, const std::string& params) throw(NutException) { std::string req = subcmd; if(!params.empty()) { req += " " + params; } std::string res = sendQuery("GET " + req); detectError(res); if(res.substr(0, req.size()) != req) { throw NutException("Invalid response"); } return explode(res, req.size()); } std::vector > TcpClient::list (const std::string& subcmd, const std::string& params) throw(NutException) { std::string req = subcmd; if(!params.empty()) { req += " " + params; } std::string res = sendQuery("LIST " + req); detectError(res); if(res != ("BEGIN LIST " + req)) { throw NutException("Invalid response"); } std::vector > arr; while(true) { res = _socket->read(); detectError(res); if(res == ("END LIST " + req)) { return arr; } if(res.substr(0, req.size()) == req) { arr.push_back(explode(res, req.size())); } else { throw NutException("Invalid response"); } } } std::string TcpClient::sendQuery(const std::string& req)throw(IOException) { _socket->write(req); return _socket->read(); } void TcpClient::detectError(const std::string& req)throw(NutException) { if(req.substr(0,3)=="ERR") { throw NutException(req.substr(4)); } } std::vector TcpClient::explode(const std::string& str, size_t begin) { std::vector res; std::string temp; enum STATE { INIT, SIMPLE_STRING, QUOTED_STRING, SIMPLE_ESCAPE, QUOTED_ESCAPE } state = INIT; for(size_t idx=begin; idxgetDeviceDescription(getName()); } std::vector Device::getVariableValue(const std::string& name) throw(NutException) { return getClient()->getDeviceVariableValue(getName(), name); } std::map > Device::getVariableValues() throw(NutException) { return getClient()->getDeviceVariableValues(getName()); } std::set Device::getVariableNames()throw(NutException) { return getClient()->getDeviceVariableNames(getName()); } std::set Device::getRWVariableNames()throw(NutException) { return getClient()->getDeviceRWVariableNames(getName()); } void Device::setVariable(const std::string& name, const std::string& value)throw(NutException) { getClient()->setDeviceVariable(getName(), name, value); } void Device::setVariable(const std::string& name, const std::vector& values) throw(NutException) { getClient()->setDeviceVariable(getName(), name, values); } Variable Device::getVariable(const std::string& name)throw(NutException) { if(getClient()->hasDeviceVariable(getName(), name)) return Variable(this, name); else return Variable(NULL, ""); } std::set Device::getVariables()throw(NutException) { std::set set; std::set names = getClient()->getDeviceVariableNames(getName()); for(std::set::iterator it=names.begin(); it!=names.end(); ++it) { set.insert(Variable(this, *it)); } return set; } std::set Device::getRWVariables()throw(NutException) { std::set set; std::set names = getClient()->getDeviceRWVariableNames(getName()); for(std::set::iterator it=names.begin(); it!=names.end(); ++it) { set.insert(Variable(this, *it)); } return set; } std::set Device::getCommandNames()throw(NutException) { return getClient()->getDeviceCommandNames(getName()); } std::set Device::getCommands()throw(NutException) { std::set cmds; std::set res = getCommandNames(); for(std::set::iterator it=res.begin(); it!=res.end(); ++it) { cmds.insert(Command(this, *it)); } return cmds; } Command Device::getCommand(const std::string& name)throw(NutException) { if(getClient()->hasDeviceCommand(getName(), name)) return Command(this, name); else return Command(NULL, ""); } void Device::executeCommand(const std::string& name)throw(NutException) { getClient()->executeDeviceCommand(getName(), name); } void Device::login()throw(NutException) { getClient()->deviceLogin(getName()); } void Device::master()throw(NutException) { getClient()->deviceMaster(getName()); } void Device::forcedShutdown()throw(NutException) { } int Device::getNumLogins()throw(NutException) { return getClient()->deviceGetNumLogins(getName()); } /* * * Variable implementation * */ Variable::Variable(Device* dev, const std::string& name): _device(dev), _name(name) { } Variable::Variable(const Variable& var): _device(var._device), _name(var._name) { } Variable::~Variable() { } std::string Variable::getName()const { return _name; } const Device* Variable::getDevice()const { return _device; } Device* Variable::getDevice() { return _device; } bool Variable::isOk()const { return _device!=NULL && !_name.empty(); } Variable::operator bool()const { return isOk(); } bool Variable::operator!()const { return !isOk(); } bool Variable::operator==(const Variable& var)const { return var._device==_device && var._name==_name; } bool Variable::operator<(const Variable& var)const { return getName() Variable::getValue()throw(NutException) { return getDevice()->getClient()->getDeviceVariableValue(getDevice()->getName(), getName()); } std::string Variable::getDescription()throw(NutException) { return getDevice()->getClient()->getDeviceVariableDescription(getDevice()->getName(), getName()); } void Variable::setValue(const std::string& value)throw(NutException) { getDevice()->setVariable(getName(), value); } void Variable::setValues(const std::vector& values)throw(NutException) { getDevice()->setVariable(getName(), values); } /* * * Command implementation * */ Command::Command(Device* dev, const std::string& name): _device(dev), _name(name) { } Command::Command(const Command& cmd): _device(cmd._device), _name(cmd._name) { } Command::~Command() { } std::string Command::getName()const { return _name; } const Device* Command::getDevice()const { return _device; } Device* Command::getDevice() { return _device; } bool Command::isOk()const { return _device!=NULL && !_name.empty(); } Command::operator bool()const { return isOk(); } bool Command::operator!()const { return !isOk(); } bool Command::operator==(const Command& cmd)const { return cmd._device==_device && cmd._name==_name; } bool Command::operator<(const Command& cmd)const { return getName()getClient()->getDeviceCommandDescription(getDevice()->getName(), getName()); } void Command::execute()throw(NutException) { getDevice()->executeCommand(getName()); } } /* namespace nut */ /** * C nutclient API. */ extern "C" { strarr strarr_alloc(unsigned short count) { strarr arr = (strarr)xcalloc(count+1, sizeof(char*)); arr[count] = NULL; return arr; } void strarr_free(strarr arr) { char** pstr = arr; while(*pstr!=NULL) { free(*pstr); ++pstr; } free(arr); } static strarr stringset_to_strarr(const std::set& strset) { strarr arr = strarr_alloc(strset.size()); strarr pstr = arr; for(std::set::const_iterator it=strset.begin(); it!=strset.end(); ++it) { *pstr = xstrdup(it->c_str()); } return arr; } static strarr stringvector_to_strarr(const std::vector& strset) { strarr arr = strarr_alloc(strset.size()); strarr pstr = arr; for(std::vector::const_iterator it=strset.begin(); it!=strset.end(); ++it) { *pstr = xstrdup(it->c_str()); } return arr; } NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, unsigned short port) { nut::TcpClient* client = new nut::TcpClient; try { client->connect(host, port); return (NUTCLIENT_TCP_t)client; } catch(nut::NutException& ex) { // TODO really catch it delete client; return NULL; } } void nutclient_destroy(NUTCLIENT_t client) { if(client) { delete (nut::Client*)client; } } int nutclient_tcp_is_connected(NUTCLIENT_TCP_t client) { if(client) { nut::TcpClient* cl = dynamic_cast((nut::Client*)client); if(cl) { return cl->isConnected() ? 1 : 0; } } return 0; } void nutclient_tcp_disconnect(NUTCLIENT_TCP_t client) { if(client) { nut::TcpClient* cl = dynamic_cast((nut::Client*)client); if(cl) { cl->disconnect(); } } } int nutclient_tcp_reconnect(NUTCLIENT_TCP_t client) { if(client) { nut::TcpClient* cl = dynamic_cast((nut::Client*)client); if(cl) { try { cl->connect(); return 0; } catch(...){} } } return -1; } void nutclient_tcp_set_timeout(NUTCLIENT_TCP_t client, long timeout) { if(client) { nut::TcpClient* cl = dynamic_cast((nut::Client*)client); if(cl) { cl->setTimeout(timeout); } } } long nutclient_tcp_get_timeout(NUTCLIENT_TCP_t client) { if(client) { nut::TcpClient* cl = dynamic_cast((nut::Client*)client); if(cl) { return cl->getTimeout(); } } return -1; } void nutclient_authenticate(NUTCLIENT_t client, const char* login, const char* passwd) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->authenticate(login, passwd); } catch(...){} } } } void nutclient_logout(NUTCLIENT_t client) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->logout(); } catch(...){} } } } void nutclient_device_login(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->deviceLogin(dev); } catch(...){} } } } int nutclient_get_device_num_logins(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return cl->deviceGetNumLogins(dev); } catch(...){} } } return -1; } void nutclient_device_master(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->deviceMaster(dev); } catch(...){} } } } void nutclient_device_forced_shutdown(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->deviceForcedShutdown(dev); } catch(...){} } } } strarr nutclient_get_devices(NUTCLIENT_t client) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return stringset_to_strarr(cl->getDeviceNames()); } catch(...){} } } return NULL; } int nutclient_has_device(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return cl->hasDevice(dev)?1:0; } catch(...){} } } return 0; } char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return xstrdup(cl->getDeviceDescription(dev).c_str()); } catch(...){} } } return NULL; } strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return stringset_to_strarr(cl->getDeviceVariableNames(dev)); } catch(...){} } } return NULL; } strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return stringset_to_strarr(cl->getDeviceRWVariableNames(dev)); } catch(...){} } } return NULL; } int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const char* var) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return cl->hasDeviceVariable(dev, var)?1:0; } catch(...){} } } return 0; } char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* dev, const char* var) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return xstrdup(cl->getDeviceVariableDescription(dev, var).c_str()); } catch(...){} } } return NULL; } strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return stringvector_to_strarr(cl->getDeviceVariableValue(dev, var)); } catch(...){} } } return NULL; } void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, const char* var, const char* value) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->setDeviceVariable(dev, var, value); } catch(...){} } } } void nutclient_set_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var, const strarr values) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { std::vector vals; strarr pstr = (strarr)values; while(*pstr) { vals.push_back(std::string(*pstr)); ++pstr; } cl->setDeviceVariable(dev, var, vals); } catch(...){} } } } strarr nutclient_get_device_commands(NUTCLIENT_t client, const char* dev) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return stringset_to_strarr(cl->getDeviceCommandNames(dev)); } catch(...){} } } return NULL; } int nutclient_has_device_command(NUTCLIENT_t client, const char* dev, const char* cmd) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return cl->hasDeviceCommand(dev, cmd)?1:0; } catch(...){} } } return 0; } char* nutclient_get_device_command_description(NUTCLIENT_t client, const char* dev, const char* cmd) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { return xstrdup(cl->getDeviceCommandDescription(dev, cmd).c_str()); } catch(...){} } } return NULL; } void nutclient_execute_device_command(NUTCLIENT_t client, const char* dev, const char* cmd) { if(client) { nut::Client* cl = (nut::Client*)client; if(cl) { try { cl->executeDeviceCommand(dev, cmd); } catch(...){} } } } } /* extern "C" */