Exemple #1
0
int cast2int(struct varcont_t **a) {
	struct varcont_t b;
	memset(&b, 0, sizeof(struct varcont_t));

	b.type_ = JSON_NUMBER;

	if((*a)->type_ == JSON_STRING) {
		b.number_  = atof((*a)->string_);
		if(b.number_ != 0) {
			b.decimals_ = nrDecimals((*a)->string_);
		}
		if((*a)->free_ == 1) {
			FREE((*a)->string_);
			(*a)->free_ = 0;
		}
	}
	if((*a)->type_ == JSON_BOOL) {
		if((*a)->bool_ == 0) {
			b.number_ = 0;
		} else {
			b.number_ = 1;
		}
	}
	if((*a)->type_ == JSON_NUMBER) {
		b.number_ = (*a)->number_;
		b.decimals_ = (*a)->decimals_;
	}

	memcpy(*a, &b, sizeof(struct varcont_t));
	return 0;
}
Exemple #2
0
static int plua_operator_precedence_run(struct lua_State *L, char *file, int *ret) {
#if LUA_VERSION_NUM <= 502
	lua_getfield(L, -1, "precedence");
	if(lua_type(L, -1) != LUA_TFUNCTION) {
#else
	if(lua_getfield(L, -1, "precedence") == 0) {
#endif
		logprintf(LOG_ERR, "%s: precedence function missing", file);
		return 0;
	}

	if(lua_pcall(L, 0, 1, 0) == LUA_ERRRUN) {
		if(lua_type(L, -1) == LUA_TNIL) {
			logprintf(LOG_ERR, "%s: syntax error", file);
			return 0;
		}
		if(lua_type(L, -1) == LUA_TSTRING) {
			logprintf(LOG_ERR, "%s", lua_tostring(L,  -1));
			lua_pop(L, 1);
			return 0;
		}
	}

	if(lua_isnumber(L, -1) == 0) {
		logprintf(LOG_ERR, "%s: the precedence function returned %s, number expected", file, lua_typename(L, lua_type(L, -1)));
		return 0;
	}

	*ret = lua_tonumber(L, -1);

	lua_pop(L, 1);

	return 1;
}

static int plua_operator_associativity_run(struct lua_State *L, char *file, int *ret) {
#if LUA_VERSION_NUM <= 502
	lua_getfield(L, -1, "associativity");
	if(lua_type(L, -1) != LUA_TFUNCTION) {
#else
	if(lua_getfield(L, -1, "associativity") == 0) {
#endif
		logprintf(LOG_ERR, "%s: associativity function missing", file);
		return 0;
	}

	if(lua_pcall(L, 0, 1, 0) == LUA_ERRRUN) {
		if(lua_type(L, -1) == LUA_TNIL) {
			logprintf(LOG_ERR, "%s: syntax error", file);
			return 0;
		}
		if(lua_type(L, -1) == LUA_TSTRING) {
			logprintf(LOG_ERR, "%s", lua_tostring(L,  -1));
			lua_pop(L, 1);
			return 0;
		}
	}

	if(lua_isnumber(L, -1) == 0) {
		logprintf(LOG_ERR, "%s: the associativity function returned %s, number expected", file, lua_typename(L, lua_type(L, -1)));
		return 0;
	}

	*ret = lua_tonumber(L, -1);

	lua_pop(L, 1);

	return 1;
}

static int plua_operator_module_run(struct lua_State *L, char *file, struct varcont_t *a, struct varcont_t *b, struct varcont_t *v) {
#if LUA_VERSION_NUM <= 502
	lua_getfield(L, -1, "run");
	if(lua_type(L, -1) != LUA_TFUNCTION) {
#else
	if(lua_getfield(L, -1, "run") == 0) {
#endif
		logprintf(LOG_ERR, "%s: run function missing", file);
		return 0;
	}

	switch(a->type_) {
		case JSON_NUMBER: {
			lua_pushnumber(L, a->number_);
		} break;
		case JSON_STRING:
			lua_pushstring(L, a->string_);
		break;
		case JSON_BOOL:
			lua_pushboolean(L, a->bool_);
		break;
	}
	switch(b->type_) {
		case JSON_NUMBER: {
			lua_pushnumber(L, b->number_);
		} break;
		case JSON_STRING:
			lua_pushstring(L, b->string_);
		break;
		case JSON_BOOL:
			lua_pushboolean(L, b->bool_);
		break;
	}

	if(lua_pcall(L, 2, 1, 0) == LUA_ERRRUN) {
		if(lua_type(L, -1) == LUA_TNIL) {
			logprintf(LOG_ERR, "%s: syntax error", file);
			return 0;
		}
		if(lua_type(L, -1) == LUA_TSTRING) {
			logprintf(LOG_ERR, "%s", lua_tostring(L,  -1));
			lua_pop(L, 1);
			return 0;
		}
	}

	if(lua_isstring(L, -1) == 0 &&
		lua_isnumber(L, -1) == 0 &&
		lua_isboolean(L, -1) == 0) {
		logprintf(LOG_ERR, "%s: the run function returned %s, string, number or boolean expected", file, lua_typename(L, lua_type(L, -1)));
		return 0;
	}

	if(lua_isnumber(L, -1) == 1) {
		char *p = (char *)lua_tostring(L, -1);
		v->number_ = atof(p);
		v->decimals_ = nrDecimals(p);
		v->type_ = JSON_NUMBER;
	} else if(lua_isstring(L, -1) == 1) {
		int l = strlen(lua_tostring(L, -1));
		if((v->string_ = REALLOC(v->string_, l+1)) == NULL) {
			OUT_OF_MEMORY
		}
		strcpy(v->string_, lua_tostring(L, -1));
		v->type_ = JSON_STRING;
		v->free_ = 1;
	} else if(lua_isboolean(L, -1) == 1) {
Exemple #3
0
static int plua_function_module_run(struct lua_State *L, char *file, struct event_function_args_t *args, struct varcont_t *v) {
#if LUA_VERSION_NUM <= 502
	lua_getfield(L, -1, "run");
	if(lua_type(L, -1) != LUA_TFUNCTION) {
#else
	if(lua_getfield(L, -1, "run") == 0) {
#endif
		logprintf(LOG_ERR, "%s: run function missing", file);
		return 0;
	}

	int nrargs = 0;
	struct event_function_args_t *tmp1 = NULL;
	while(args) {
		tmp1 = args;
		nrargs++;
		switch(tmp1->var.type_) {
			case JSON_NUMBER: {
				char *tmp = NULL;
				int len = snprintf(NULL, 0, "%.*f", tmp1->var.decimals_, tmp1->var.number_);
				if((tmp = MALLOC(len+1)) == NULL) {
					OUT_OF_MEMORY /*LCOV_EXCL_LINE*/
				}
				memset(tmp, 0, len+1);
				sprintf(tmp, "%.*f", tmp1->var.decimals_, tmp1->var.number_);
				lua_pushstring(L, tmp);
				FREE(tmp);
			} break;
			case JSON_STRING:
				lua_pushstring(L, tmp1->var.string_);
				FREE(tmp1->var.string_);
			break;
			case JSON_BOOL:
				lua_pushboolean(L, tmp1->var.bool_);
			break;
		}
		args = args->next;
		FREE(tmp1);
	}
	args = NULL;

	if(lua_pcall(L, nrargs, 1, 0) == LUA_ERRRUN) {
		if(lua_type(L, -1) == LUA_TNIL) {
			logprintf(LOG_ERR, "%s: syntax error", file);
			return 0;
		}
		if(lua_type(L, -1) == LUA_TSTRING) {
			logprintf(LOG_ERR, "%s", lua_tostring(L,  -1));
			lua_pop(L, 1);
			return 0;
		}
	}

	if(lua_isstring(L, -1) == 0 &&
		lua_isnumber(L, -1) == 0 &&
		lua_isboolean(L, -1) == 0) {
		logprintf(LOG_ERR, "%s: the run function returned %s, string, number or boolean expected", file, lua_typename(L, lua_type(L, -1)));
		return 0;
	}

	if(lua_isnumber(L, -1) == 1) {
		char *p = (char *)lua_tostring(L, -1);
		v->number_ = atof(p);
		v->decimals_ = nrDecimals(p);
		v->type_ = JSON_NUMBER;
	} else if(lua_isstring(L, -1) == 1) {
		int l = strlen(lua_tostring(L, -1));
		if((v->string_ = REALLOC(v->string_, l+1)) == NULL) {
			OUT_OF_MEMORY
		}
		strcpy(v->string_, lua_tostring(L, -1));
		v->type_ = JSON_STRING;
		v->free_ = 1;
	} else if(lua_isboolean(L, -1) == 1) {
Exemple #4
0
static int event_parse_action(char *action, struct rules_t *obj, int validate) {
	logprintf(LOG_STACK, "%s(...)", __FUNCTION__);

	struct JsonNode *jvalues = NULL;
	char *var1 = NULL, *func = NULL, *var2 = NULL, *tmp = action;
	char *var3 = NULL, *var4 = NULL;
	int element = 0, match = 0, error = 0, order = 0;
	int hasaction = 0, hasquote = 0, match1 = 0, match2 = 0;
	unsigned long len = strlen(tmp), pos = 0, word = 0, hadquote = 0;

	if(obj->arguments == NULL) {
		obj->arguments = json_mkobject();
		while(pos <= len) {
			/* If we encounter a space we have the formula part */
			if(tmp[pos] == '"') {
				hasquote ^= 1;
				if(hasquote == 1) {
					word++;
				} else {
					hadquote = 1;
				}
			}
			if(hasquote == 0 && (tmp[pos] == ' ' || pos == len)) {
				switch(element) {
					/* The first value of three is always the first variable.
						 The second value is always the function.
						 The third value of the three is always the second variable (or second formula).
					*/
					case 0:
						var1 = REALLOC(var1, ((pos-word)+1));
						memset(var1, '\0', ((pos-word)+1));
						strncpy(var1, &tmp[word], (pos-word)-hadquote);
					break;
					case 1:
						func = REALLOC(func, ((pos-word)+1));
						memset(func, '\0', ((pos-word)+1));
						strncpy(func, &tmp[word], (pos-word)-hadquote);
					break;
					case 2:
						var2 = REALLOC(var2, ((pos-word)+1));
						memset(var2, '\0', ((pos-word)+1));
						strncpy(var2, &tmp[word], (pos-word)-hadquote);
					break;
					default:;
				}
				hadquote = 0;
				word = pos+1;
				element++;
				if(element > 2) {
					element = 0;
				}
			}
			if(hasaction == 0 && var1 && strlen(var1) > 0) {
				match = 0;
				obj->action = event_actions;
				while(obj->action) {
					if(strcmp(obj->action->name, var1) == 0) {
						match = 1;
						break;
					}
					obj->action = obj->action->next;
				}
				if(match == 1) {
					hasaction = 1;
					element = 0;
				} else {
					logprintf(LOG_ERR, "action \"%s\" doesn't exists", var1);
					error = 1;
					break;
				}
			} else if(func && strlen(func) > 0 &&
				 var1 && strlen(var1) > 0 &&
				 var2 && strlen(var2) > 0) {
				 int hasand = 0;
				if(strcmp(var2, "AND") == 0) {
					hasand = 1;
					word -= strlen(var2)+1;
					if(jvalues == NULL) {
						jvalues = json_mkarray();
					}
					if(isNumeric(func) == 0) {
						json_append_element(jvalues, json_mknumber(atof(func), nrDecimals(func)));
					} else {
						json_append_element(jvalues, json_mkstring(func));
					}
					element = 0;
					while(pos <= len) {
						if(tmp[pos] == '"') {
							hasquote ^= 1;
							if(hasquote == 1) {
								word++;
							} else {
								hadquote = 1;
							}
						}
						if(hasquote == 0 && (tmp[pos] == ' ' || pos == len)) {
							switch(element) {
								/* The first value of three is always the first variable.
									 The second value is always the function.
									 The third value of the three is always the second variable (or second formula).
								*/
								case 0:
									var3 = REALLOC(var3, ((pos-word)+1));
									memset(var3, '\0', ((pos-word)+1));
									strncpy(var3, &tmp[word], (pos-word)-hadquote);
								break;
								case 1:
									var4 = REALLOC(var4, ((pos-word)+1));
									memset(var4, '\0', ((pos-word)+1));
									strncpy(var4, &tmp[word], (pos-word)-hadquote);
								break;
								default:;
							}
							hadquote = 0;
							word = pos+1;
							element++;
							if(element > 1) {
								element = 0;
							}
						}
						pos++;
						if(var3 && strlen(var3) > 0 &&
							 var4 && strlen(var4) > 0) {
							if(strcmp(var3, "AND") != 0) {
								var2 = REALLOC(var2, strlen(var3)+1);
								strcpy(var2, var3);
								pos -= strlen(var3)+strlen(var4)+2;
								word -= strlen(var3)+strlen(var4)+2;
								break;
							}
							if(isNumeric(var4) == 0) {
								json_append_element(jvalues, json_mknumber(atof(var4), nrDecimals(var4)));
							} else {
								json_append_element(jvalues, json_mkstring(var4));
							}
							element = 0;
							if(var3) {
								memset(var3, '\0', strlen(var3));
							} if(var4) {
								memset(var4, '\0', strlen(var4));
							}
						}
					}
				}
				match1 = 0, match2 = 0;
				struct options_t *opt = obj->action->options;
				while(opt) {
					if(strcmp(opt->name, var1) == 0) {
						match1 = 1;
					}
					if(strcmp(opt->name, var2) == 0) {
						match2 = 1;
					}
					if(match1 == 1 && match2 == 1) {
						break;
					}
					opt = opt->next;
				}
				/* If we are at the end of our rule
					 we only match the first option */
				if(pos == len+1) {
					match2 = 1;
				}
				if(match1 == 1 && match2 == 1) {
					struct JsonNode *jobj = json_mkobject();
					order++;
					if(hasand == 1) {
						json_append_member(jobj, "value", jvalues);
						json_append_member(jobj, "order", json_mknumber(order, 0));
						jvalues = NULL;
					} else {
						jvalues = json_mkarray();
						if(isNumeric(func) == 0) {
							json_append_element(jvalues, json_mknumber(atof(func), nrDecimals(func)));
							json_append_member(jobj, "value", jvalues);
							json_append_member(jobj, "order", json_mknumber(order, 0));
							jvalues = NULL;
						} else {
							json_append_element(jvalues, json_mkstring(func));
							json_append_member(jobj, "value", jvalues);
							json_append_member(jobj, "order", json_mknumber(order, 0));
							jvalues = NULL;
						}
					}
					json_append_member(obj->arguments, var1, jobj);
				} else if(match1 == 0) {
					logprintf(LOG_ERR, "action \"%s\" doesn't accept option \"%s\"", obj->action->name, var1);
					error = 1;
					if(jvalues) {
						json_delete(jvalues);
					}
					break;
				} else if(match2 == 0) {
					logprintf(LOG_ERR, "action \"%s\" doesn't accept option \"%s\"", obj->action->name, var2);
					error = 1;
					if(jvalues) {
						json_delete(jvalues);
					}
					break;
				}
				element = 0, match1 = 0, match2 = 0;
				if(hasand == 0) {
					pos -= strlen(var2)+1;
					word -= strlen(var2)+1;
				}
				if(var1) {
					memset(var1, '\0', strlen(var1));
				} if(func) {
					memset(func, '\0', strlen(func));
				} if(var2) {
					memset(var2, '\0', strlen(var2));
				} if(var3) {
					memset(var3, '\0', strlen(var3));
				} if(var4) {
					memset(var4, '\0', strlen(var4));
				}
				hasand = 0;
			}
			pos++;
		}
		if(error == 0) {
			if(var1 && strlen(var1) > 0 &&
				 func && strlen(func) > 0) {
				match1 = 0;
				struct options_t *opt = obj->action->options;
				while(opt) {
					if(strcmp(opt->name, var1) == 0) {
						match1 = 1;
					}
					if(match1 == 1) {
						break;
					}
					opt = opt->next;
				}
				if(match1 == 1) {
					struct JsonNode *jobj = json_mkobject();
					order++;
					jvalues = json_mkarray();
					if(isNumeric(func) == 0) {
						json_append_element(jvalues, json_mknumber(atof(func), nrDecimals(func)));
						json_append_member(jobj, "value", jvalues);
						json_append_member(jobj, "order", json_mknumber(order, 0));
						jvalues = NULL;
					} else {
						json_append_element(jvalues, json_mkstring(func));
						json_append_member(jobj, "value", jvalues);
						json_append_member(jobj, "order", json_mknumber(order, 0));
						jvalues = NULL;
					}
					json_append_member(obj->arguments, var1, jobj);
				} else {
					error = 1;
				}
			}
		}
		if(error == 0) {
			struct options_t *opt = obj->action->options;
			struct JsonNode *joption = NULL;
			struct JsonNode *jvalue = NULL;
			struct JsonNode *jchild = NULL;
			while(opt) {
				if((joption = json_find_member(obj->arguments, opt->name)) == NULL) {
					if(opt->conftype == DEVICES_VALUE) {
						logprintf(LOG_ERR, "action \"%s\" is missing option \"%s\"", obj->action->name, opt->name);
						error = 1;
						break;
					}
				} else {
					if((jvalue = json_find_member(joption, "value")) != NULL) {
						if(jvalue->tag == JSON_ARRAY) {
							jchild = json_first_child(jvalue);
							while(jchild) {
								if(jchild->tag != JSON_NUMBER && opt->vartype == JSON_NUMBER) {
									logprintf(LOG_ERR, "action \"%s\" option \"%s\" only accepts numbers", obj->action->name, opt->name);
									error = 1;
									break;
								}
								if(jchild->tag != JSON_STRING && opt->vartype == JSON_STRING) {
									logprintf(LOG_ERR, "action \"%s\" option \"%s\" only accepts strings", obj->action->name, opt->name);
									error = 1;
									break;
								}
								jchild = jchild->next;
							}
						}
					}
				}
				opt = opt->next;
			}
			if(error == 0) {
				jchild = json_first_child(obj->arguments);
				while(jchild) {
					match = 0;
					opt = obj->action->options;
					while(opt) {
						if(strcmp(jchild->key, opt->name) == 0) {
							match = 1;
							break;
						}
						opt = opt->next;
					}
					if(match == 0) {
						logprintf(LOG_ERR, "action \"%s\" doesn't accept option \"%s\"", obj->action->name, jchild->key);
						error = 1;
						break;
					}
					jchild = jchild->next;
				}
			}
		}
	}

	if(error == 0) {
		if(validate == 1) {
			if(obj->action->checkArguments) {
				error = obj->action->checkArguments(obj->arguments);
			}
		} else {
			if(obj->action->run) {
				error = obj->action->run(obj->arguments);
			}
		}
	}
	if(var1) {
		FREE(var1);
		var1 = NULL;
	} if(func) {
		FREE(func);
		func = NULL;
	} if(var2) {
		FREE(var2);
		var2 = NULL;
	}	if(var3) {
		FREE(var3);
		var3 = NULL;
	} if(var4) {
		FREE(var4);
		var4 = NULL;
	}
	return error;
}
Exemple #5
0
int main(int argc, char **argv) {
	// memtrack();

	atomicinit();
	struct options_t *options = NULL;
	struct ssdp_list_t *ssdp_list = NULL;
	struct devices_t *dev = NULL;
	struct JsonNode *json = NULL;
	struct JsonNode *tmp = NULL;
	char *recvBuff = NULL, *message = NULL, *output = NULL;
	char *device = NULL, *state = NULL, *values = NULL;
	char *server = NULL;
	int has_values = 0, sockfd = 0, hasconfarg = 0;
	unsigned short port = 0, showhelp = 0, showversion = 0;

	log_file_disable();
	log_shell_enable();
	log_level_set(LOG_NOTICE);

#ifndef _WIN32
	wiringXLog = logprintf;
#endif

	if((progname = MALLOC(16)) == NULL) {
		fprintf(stderr, "out of memory\n");
		exit(EXIT_FAILURE);
	}
	strcpy(progname, "pilight-control");

	/* 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, 'd', "device", OPTION_HAS_VALUE, 0,  JSON_NULL, NULL, NULL);
	options_add(&options, 's', "state", OPTION_HAS_VALUE, 0, JSON_NULL, NULL, NULL);
	options_add(&options, 'v', "values", 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, 'C', "config", OPTION_HAS_VALUE, 0, JSON_NULL, NULL, NULL);

	/* 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, 1, &optarg);
		if(c == -1)
			break;
		if(c == -2) {
			showhelp = 1;
			break;
		}
		switch(c) {
			case 'H':
				showhelp = 1;
			break;
			case 'V':
				showversion = 1;
			break;
			case 'd':
				if((device = REALLOC(device, strlen(optarg)+1)) == NULL) {
					fprintf(stderr, "out of memory\n");
					exit(EXIT_FAILURE);
				}
				strcpy(device, optarg);
			break;
			case 's':
				if((state = REALLOC(state, strlen(optarg)+1)) == NULL) {
					fprintf(stderr, "out of memory\n");
					exit(EXIT_FAILURE);
				}
				strcpy(state, optarg);
			break;
			case 'v':
				if((values = REALLOC(values, strlen(optarg)+1)) == NULL) {
					fprintf(stderr, "out of memory\n");
					exit(EXIT_FAILURE);
				}
				strcpy(values, optarg);
			break;
			case 'C':
				if(config_set_file(optarg) == EXIT_FAILURE) {
					return EXIT_FAILURE;
				}
				hasconfarg = 1;
			break;
			case 'S':
				if(!(server = REALLOC(server, strlen(optarg)+1))) {
					fprintf(stderr, "out of memory\n");
					exit(EXIT_FAILURE);
				}
				strcpy(server, optarg);
			break;
			case 'P':
				port = (unsigned short)atoi(optarg);
			break;
			default:
				printf("Usage: %s -l location -d device -s state\n", progname);
				goto close;
			break;
		}
	}
	options_delete(options);

	if(showversion == 1) {
		printf("%s v%s\n", progname, PILIGHT_VERSION);
		goto close;
	}
	if(showhelp == 1) {
		printf("\t -H --help\t\t\tdisplay this message\n");
		printf("\t -V --version\t\t\tdisplay version\n");
		printf("\t -S --server=x.x.x.x\t\tconnect to server address\n");
		printf("\t -C --config\t\t\tconfig file\n");
		printf("\t -P --port=xxxx\t\t\tconnect to server port\n");
		printf("\t -d --device=device\t\tthe device that you want to control\n");
		printf("\t -s --state=state\t\tthe new state of the device\n");
		printf("\t -v --values=values\t\tspecific comma separated values, e.g.:\n");
		printf("\t\t\t\t\t-v dimlevel=10\n");
		goto close;
	}
	if(device == NULL || state == NULL ||
	   strlen(device) == 0 || strlen(state) == 0) {
		printf("Usage: %s -d device -s state\n", progname);
		goto close;
	}

	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);
	}

	protocol_init();
	config_init();
	if(hasconfarg == 1) {
		if(config_read() != EXIT_SUCCESS) {
			goto close;
		}
	}

	socket_write(sockfd, "{\"action\":\"identify\"}");
	if(socket_read(sockfd, &recvBuff, 0) != 0
	   || strcmp(recvBuff, "{\"status\":\"success\"}") != 0) {
		goto close;
	}

	json = json_mkobject();
	json_append_member(json, "action", json_mkstring("request config"));
	output = json_stringify(json, NULL);
	socket_write(sockfd, output);
	json_free(output);
	json_delete(json);

	if(socket_read(sockfd, &recvBuff, 0) == 0) {
		if(json_validate(recvBuff) == true) {
			json = json_decode(recvBuff);
			if(json_find_string(json, "message", &message) == 0) {
				if(strcmp(message, "config") == 0) {
					struct JsonNode *jconfig = NULL;
					if((jconfig = json_find_member(json, "config")) != NULL) {
						int match = 1;
						while(match) {
							struct JsonNode *jchilds = json_first_child(jconfig);
							match = 0;
							while(jchilds) {
								if(strcmp(jchilds->key, "devices") != 0) {
									json_remove_from_parent(jchilds);
									tmp = jchilds;
									match = 1;
								}
								jchilds = jchilds->next;
								if(tmp != NULL) {
									json_delete(tmp);
								}
								tmp = NULL;
							}
						}
						config_parse(jconfig);
						if(devices_get(device, &dev) == 0) {
							JsonNode *joutput = json_mkobject();
							JsonNode *jcode = json_mkobject();
							JsonNode *jvalues = json_mkobject();
							json_append_member(jcode, "device", json_mkstring(device));

							if(values != NULL) {
								char **array = NULL;
								unsigned int n = explode(values, ",=", &array), q = 0;
								for(q=0;q<n;q+=2) {
									char *name = MALLOC(strlen(array[q])+1);
									if(name == NULL) {
										logprintf(LOG_ERR, "out of memory\n");
										exit(EXIT_FAILURE);
									}
									strcpy(name, array[q]);
									if(q+1 == n) {
										array_free(&array, n);
										logprintf(LOG_ERR, "\"%s\" is missing a value for device \"%s\"", name, device);
										FREE(name);
										break;
									} else {
										char *val = MALLOC(strlen(array[q+1])+1);
										if(val == NULL) {
											logprintf(LOG_ERR, "out of memory\n");
											exit(EXIT_FAILURE);
										}
										strcpy(val, array[q+1]);
										if(devices_valid_value(device, name, val) == 0) {
											if(isNumeric(val) == EXIT_SUCCESS) {
												json_append_member(jvalues, name, json_mknumber(atof(val), nrDecimals(val)));
											} else {
												json_append_member(jvalues, name, json_mkstring(val));
											}
											has_values = 1;
										} else {
											logprintf(LOG_ERR, "\"%s\" is an invalid value for device \"%s\"", name, device);
											array_free(&array, n);
											FREE(name);
											json_delete(json);
											goto close;
										}
									}
									FREE(name);
								}
								array_free(&array, n);
							}

							if(devices_valid_state(device, state) == 0) {
								json_append_member(jcode, "state", json_mkstring(state));
							} else {
								logprintf(LOG_ERR, "\"%s\" is an invalid state for device \"%s\"", state, device);
								json_delete(json);
								goto close;
							}

							if(has_values == 1) {
								json_append_member(jcode, "values", jvalues);
							} else {
								json_delete(jvalues);
							}
							json_append_member(joutput, "action", json_mkstring("control"));
							json_append_member(joutput, "code", jcode);
							output = json_stringify(joutput, NULL);
							socket_write(sockfd, output);
							json_free(output);
							json_delete(joutput);
							if(socket_read(sockfd, &recvBuff, 0) != 0
							   || strcmp(recvBuff, "{\"status\":\"success\"}") != 0) {
								logprintf(LOG_ERR, "failed to control %s", device);
							}
						} else {
							logprintf(LOG_ERR, "the device \"%s\" does not exist", device);
							json_delete(json);
							goto close;
						}
					}
				}
			}
			json_delete(json);
		}
	}
close:
	if(recvBuff) {
		FREE(recvBuff);
	}
	if(sockfd > 0) {
		socket_close(sockfd);
	}
	if(server != NULL) {
		FREE(server);
	}
	if(device != NULL) {
		FREE(device);
	}
	if(state != NULL) {
		FREE(state);
	}
	if(values != NULL) {
		FREE(values);
	}
	log_shell_disable();
	socket_gc();
	config_gc();
	protocol_gc();
	options_gc();
#ifdef EVENTS
	events_gc();
#endif
	dso_gc();
	log_gc();
	threads_gc();
	gc_clear();
	FREE(progname);
	xfree();

#ifdef _WIN32
	WSACleanup();
#endif

	return EXIT_SUCCESS;
}