Files
OpenMQTT-Gateway/lib/ESPiLight/pilight/send.c
T
Florian 67dd7ac078 update esppilight lib
content of the library is not filtered on 433mhz only
2018-11-28 20:41:37 +01:00

419 lines
11 KiB
C

/*
Copyright (C) 2013 - 2014 CurlyMo
This file is part of pilight.
pilight 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 3 of the License, or (at your option) any later
version.
pilight 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 pilight. If not, see <http://www.gnu.org/licenses/>
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifndef _WIN32
#include <wiringx.h>
#endif
#include "libs/pilight/core/threads.h"
#include "libs/pilight/core/pilight.h"
#include "libs/pilight/core/common.h"
#include "libs/pilight/core/config.h"
#include "libs/pilight/core/log.h"
#include "libs/pilight/core/options.h"
#include "libs/pilight/core/socket.h"
#include "libs/pilight/core/json.h"
#include "libs/pilight/core/ssdp.h"
#include "libs/pilight/core/dso.h"
#include "libs/pilight/protocols/protocol.h"
typedef struct pname_t {
char *name;
char *desc;
struct pname_t *next;
} pname_t;
static struct pname_t *pname = NULL;
static void sort_list(void) {
struct pname_t *a = NULL;
struct pname_t *b = NULL;
struct pname_t *c = NULL;
struct pname_t *e = NULL;
struct pname_t *tmp = NULL;
while(pname && e != pname->next) {
c = a = pname;
b = a->next;
while(a != e) {
if(strcmp(a->name, b->name) > 0) {
if(a == pname) {
tmp = b->next;
b->next = a;
a->next = tmp;
pname = b;
c = b;
} else {
tmp = b->next;
b->next = a;
a->next = tmp;
c->next = b;
c = b;
}
} else {
c = a;
a = a->next;
}
b = a->next;
if(b == e)
e = a;
}
}
}
int main(int argc, char **argv) {
// memtrack();
atomicinit();
log_file_disable();
log_shell_enable();
log_level_set(LOG_NOTICE);
if((progname = MALLOC(13)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(progname, "pilight-send");
struct options_t *options = NULL;
struct ssdp_list_t *ssdp_list = NULL;
int sockfd = 0;
int raw[MAXPULSESTREAMLENGTH-1];
char *args = NULL, *recvBuff = NULL;
/* Hold the name of the protocol */
char *protobuffer = NULL;
/* Does this protocol exists */
int match = 0;
/* Do we need to print the help */
int help = 0;
/* Do we need to print the version */
int version = 0;
/* Do we need to print the protocol help */
int protohelp = 0;
char *uuid = NULL;
char *server = NULL;
unsigned short port = 0;
/* Hold the final protocol struct */
struct protocol_t *protocol = NULL;
JsonNode *code = NULL;
/* Define all CLI arguments of this program */
options_add(&options, 'H', "help", OPTION_NO_VALUE, 0, JSON_NULL, NULL, NULL);
options_add(&options, 'V', "version", OPTION_NO_VALUE, 0, JSON_NULL, NULL, NULL);
options_add(&options, 'p', "protocol", OPTION_HAS_VALUE, 0, JSON_NULL, NULL, NULL);
options_add(&options, 'S', "server", OPTION_HAS_VALUE, 0, JSON_NULL, NULL, "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
options_add(&options, 'P', "port", OPTION_HAS_VALUE, 0, JSON_NULL, NULL, "[0-9]{1,4}");
options_add(&options, 'U', "uuid", OPTION_HAS_VALUE, 0, JSON_NULL, NULL, "[a-zA-Z0-9]{4}-[a-zA-Z0-9]{2}-[a-zA-Z0-9]{2}-[a-zA-Z0-9]{2}-[a-zA-Z0-9]{6}");
/* Get the protocol to be used */
while(1) {
int c;
c = options_parse(&options, argc, argv, 0, &args);
if(c == -1)
break;
if(c == -2)
c = 'H';
switch(c) {
case 'p':
if(strlen(args) == 0) {
logprintf(LOG_INFO, "options '-p' and '--protocol' require an argument");
exit(EXIT_FAILURE);
} else {
if((protobuffer = REALLOC(protobuffer, strlen(args)+1)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(protobuffer, args);
}
break;
case 'V':
version = 1;
break;
case 'H':
help = 1;
break;
case 'S':
if((server = REALLOC(server, strlen(args)+1)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(server, args);
break;
case 'P':
port = (unsigned short)atoi(args);
break;
case 'U':
if((uuid = REALLOC(uuid, strlen(args)+1)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(uuid, args);
break;
default:;
}
}
/* Initialize protocols */
protocol_init();
/* Check if a protocol was given */
if(protobuffer != NULL && strlen(protobuffer) > 0 && strcmp(protobuffer, "-V") != 0) {
if(strlen(protobuffer) > 0 && version) {
printf("-p and -V cannot be combined\n");
} else {
struct protocols_t *pnode = protocols;
/* Retrieve the used protocol */
while(pnode) {
/* Check if the protocol exists */
protocol = pnode->listener;
if(protocol_device_exists(protocol, protobuffer) == 0 && match == 0 && protocol->createCode != NULL) {
match=1;
/* Check if the protocol requires specific CLI arguments
and merge them with the main CLI arguments */
if(protocol->options && help == 0) {
options_merge(&options, &protocol->options);
} else if(help == 1) {
protohelp=1;
}
break;
}
pnode = pnode->next;
}
/* If no protocols matches the requested protocol */
if(match == 0) {
logprintf(LOG_ERR, "this protocol is not supported or doesn't support sending");
goto close;
}
}
}
/* Store all CLI arguments for later usage
and also check if the CLI arguments where
used correctly by the user. This will also
fill all necessary values in the options struct */
while(1) {
int c;
c = options_parse(&options, argc, argv, 2, &args);
if(c == -1)
break;
if(c == -2) {
if(match == 1) {
protohelp = 1;
} else {
help = 1;
}
break;
}
}
/* Display help or version information */
if(version == 1) {
printf("%s v%s\n", progname, PILIGHT_VERSION);
goto close;
} else if(help == 1 || protohelp == 1 || match == 0) {
if(protohelp == 1 && match == 1 && protocol->printHelp)
printf("Usage: %s -p %s [options]\n", progname, protobuffer);
else
printf("Usage: %s -p protocol [options]\n", progname);
if(help == 1) {
printf("\t -H --help\t\t\tdisplay this message\n");
printf("\t -V --version\t\t\tdisplay version\n");
printf("\t -p --protocol=protocol\t\tthe protocol that you want to control\n");
printf("\t -S --server=x.x.x.x\t\tconnect to server address\n");
printf("\t -P --port=xxxx\t\t\tconnect to server port\n");
printf("\t -C --config\t\t\tconfig file\n");
printf("\t -U --uuid=xxx-xx-xx-xx-xxxxxx\tUUID\n");
}
if(protohelp == 1 && match == 1 && protocol->printHelp) {
printf("\n\t[%s]\n", protobuffer);
protocol->printHelp();
} else {
printf("\nThe supported protocols are:\n");
struct protocols_t *pnode = protocols;
/* Retrieve the used protocol */
while(pnode) {
protocol = pnode->listener;
if(protocol->createCode) {
struct protocol_devices_t *tmpdev = protocol->devices;
while(tmpdev) {
struct pname_t *node = MALLOC(sizeof(struct pname_t));
if(node == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
if((node->name = MALLOC(strlen(tmpdev->id)+1)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(node->name, tmpdev->id);
if((node->desc = MALLOC(strlen(tmpdev->desc)+1)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(node->desc, tmpdev->desc);
node->next = pname;
pname = node;
tmpdev = tmpdev->next;
}
}
pnode = pnode->next;
}
sort_list();
struct pname_t *ptmp = NULL;
while(pname) {
ptmp = pname;
printf("\t %s\t\t",ptmp->name);
if(strlen(ptmp->name) < 7)
printf("\t");
if(strlen(ptmp->name) < 15)
printf("\t");
printf("%s\n", ptmp->desc);
FREE(ptmp->name);
FREE(ptmp->desc);
pname = pname->next;
FREE(ptmp);
}
FREE(pname);
}
goto close;
}
code = json_mkobject();
int itmp = 0;
/* Check if we got sufficient arguments from this protocol */
struct options_t *tmp = options;
while(tmp) {
if(strlen(tmp->name) > 0) {
/* Only send the CLI arguments that belong to this protocol, the protocol name
and those that are called by the user */
if((options_get_id(&protocol->options, tmp->name, &itmp) == 0)
&& tmp->vartype == JSON_STRING && tmp->string_ != NULL
&& (strlen(tmp->string_) > 0)) {
if(isNumeric(tmp->string_) == 0) {
json_append_member(code, tmp->name, json_mknumber(atof(tmp->string_), nrDecimals(tmp->string_)));
} else {
json_append_member(code, tmp->name, json_mkstring(tmp->string_));
}
}
if(strcmp(tmp->name, "protocol") == 0 && strlen(tmp->string_) > 0) {
JsonNode *jprotocol = json_mkarray();
json_append_element(jprotocol, json_mkstring(tmp->string_));
json_append_member(code, "protocol", jprotocol);
}
}
tmp = tmp->next;
}
memset(raw, 0, MAXPULSESTREAMLENGTH-1);
protocol->raw = raw;
if(protocol->createCode(code) == 0) {
if(protocol->message) {
json_delete(protocol->message);
}
if(server && port > 0) {
if((sockfd = socket_connect(server, port)) == -1) {
logprintf(LOG_ERR, "could not connect to pilight-daemon");
goto close;
}
} else if(ssdp_seek(&ssdp_list) == -1) {
logprintf(LOG_NOTICE, "no pilight ssdp connections found");
goto close;
} else {
if((sockfd = socket_connect(ssdp_list->ip, ssdp_list->port)) == -1) {
logprintf(LOG_ERR, "could not connect to pilight-daemon");
goto close;
}
}
if(ssdp_list) {
ssdp_free(ssdp_list);
}
socket_write(sockfd, "{\"action\":\"identify\"}");
if(socket_read(sockfd, &recvBuff, 0) != 0
|| strcmp(recvBuff, "{\"status\":\"success\"}") != 0) {
goto close;
}
JsonNode *json = json_mkobject();
json_append_member(json, "action", json_mkstring("send"));
if(uuid != NULL) {
json_append_member(code, "uuid", json_mkstring(uuid));
}
json_append_member(json, "code", code);
char *output = json_stringify(json, NULL);
socket_write(sockfd, output);
json_free(output);
json_delete(json);
if(socket_read(sockfd, &recvBuff, 0) != 0
|| strcmp(recvBuff, "{\"status\":\"success\"}") != 0) {
logprintf(LOG_ERR, "failed to send codes");
goto close;
}
}
close:
log_shell_disable();
if(sockfd > 0) {
socket_close(sockfd);
}
if(recvBuff != NULL) {
FREE(recvBuff);
}
if(server != NULL) {
FREE(server);
}
if(protobuffer != NULL) {
FREE(protobuffer);
}
if(uuid != NULL) {
FREE(uuid);
}
protocol_gc();
options_delete(options);
options_gc();
config_gc();
threads_gc();
dso_gc();
log_gc();
FREE(progname);
xfree();
#ifdef _WIN32
WSACleanup();
#endif
return EXIT_SUCCESS;
}