Loading...
Searching...
No Matches
lirc_client.c
Go to the documentation of this file.
/****************************************************************************
** lirc_client.c ***********************************************************
****************************************************************************
*
* lirc_client - common routines for lircd clients
*
* Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
* Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
*
* System wide LIRCRC support by Michal Svec <rebel@atrey.karlin.mff.cuni.cz>
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <unistd.h>
#include "lirc_client.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 4096
#endif
static const struct timeval CMD_TIMEOUT = { .tv_sec = 1, .tv_usec = 0 };
// Until we have working client logging...
#define logprintf(level, fmt, args ...) syslog(level, fmt, ## args)
#define LIRC_WARNING LOG_WARNING
#define LIRC_DEBUG LOG_DEBUG
#define LIRC_NOTICE LOG_NOTICE
#define LIRC_ERROR LOG_ERR
/* internal defines */
#define MAX_INCLUDES 10
#define LIRC_READ 255
#define LIRC_PACKET_SIZE 255
/* three seconds */
#define LIRC_TIMEOUT 3
/* internal data structures */
struct filestack_t {
FILE* file;
char* name;
int line;
struct filestack_t* parent;
};
enum packet_state {
P_BEGIN,
P_MESSAGE,
P_STATUS,
P_DATA,
P_N,
P_DATA_N,
P_END
};
/*
* lircrc_config relies on this function, hence don't make it static
* but it's not part of the official interface, so there's no guarantee
* that it will stay available in the future
*/
unsigned int lirc_flags(char* string);
static int lirc_lircd = -1;
static int lirc_verbose = 0;
static char* lirc_prog = NULL;
static char* lirc_buffer = NULL;
char* prog;
static inline void
chk_write(int fd, const void* buf, size_t count, const char* msg)
{
if (write(fd, buf, count) == -1)
perror(msg);
}
int lirc_command_init(lirc_cmd_ctx* ctx, const char* fmt, ...)
{
va_list ap;
int n;
memset(ctx, 0, sizeof(lirc_cmd_ctx));
va_start(ap, fmt);
n = vsnprintf(ctx->packet, PACKET_SIZE, fmt, ap);
va_end(ap);
if (n >= PACKET_SIZE) {
logprintf(LIRC_NOTICE, "Message too big: %s", ctx->packet);
return EMSGSIZE;
}
return 0;
}
void lirc_command_reply_to_stdout(lirc_cmd_ctx* ctx)
{
ctx->reply_to_stdout = 1;
}
static int fill_string(int fd, lirc_cmd_ctx* cmd)
{
ssize_t n;
setsockopt(fd,
SOL_SOCKET,
SO_RCVTIMEO,
(const void*)&CMD_TIMEOUT,
sizeof(CMD_TIMEOUT));
n = read(fd, cmd->buffer + cmd->head, PACKET_SIZE - cmd->head);
if (n == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
logprintf(LIRC_NOTICE, "fill_string: timeout\n");
return EAGAIN;
}
cmd->head = 0;
return errno;
}
cmd->head += n;
return 0;
}
static int read_string(lirc_cmd_ctx* cmd, int fd, const char** string)
{
int r;
int skip;
/* Move remaining data to start of buffer, overwriting previous line. */
if (cmd->next != NULL && cmd->next != cmd->buffer) {
skip = cmd->next - cmd->buffer;
memmove(cmd->buffer, cmd->next, cmd->head - skip);
cmd->head -= skip;
cmd->next = cmd->buffer;
cmd->buffer[cmd->head] = '\0';
}
/* If no complete line is available, load more bytes from fd. */
if (cmd->next == NULL || strchr(cmd->next, '\n') == NULL) {
r = fill_string(fd, cmd);
if (r > 0)
return r;
cmd->next = cmd->buffer;
}
/* cmd->next == cmd->buffer here in all cases. */
*string = cmd->next;
/* Separate current line from the remaining lines, if available. */
cmd->next = strchr(cmd->next, '\n');
if (cmd->next != NULL) {
*(cmd->next) = '\0';
cmd->next++;
}
return 0;
}
int lirc_command_run(lirc_cmd_ctx* ctx, int fd)
{
int done, todo;
const char* string = NULL;
const char* data;
char* endptr;
enum packet_state state;
int status, n, r;
uint32_t data_n = 0;
todo = strlen(ctx->packet);
data = ctx->packet;
logprintf(LIRC_DEBUG, "lirc_command_run: Sending: %s", data);
while (todo > 0) {
done = write(fd, (void*)data, todo);
if (done < 0) {
logprintf(LIRC_WARNING,
"%s: could not send packet\n", prog);
perror(prog);
return done;
}
data += done;
todo -= done;
}
/* get response */
status = 0;
n = 0;
state = P_BEGIN;
while (1) {
do
r = read_string(ctx, fd, &string);
while (r == EAGAIN);
if (!string || strlen(string) == 0)
goto bad_packet;
logprintf(LIRC_DEBUG,
"lirc_command_run, state: %d, input: \"%s\"\n",
state, string ? string : "(Null)");
switch (state) {
case P_BEGIN:
if (strcasecmp(string, "BEGIN") != 0)
break;
state = P_MESSAGE;
continue;
case P_MESSAGE:
if (strncasecmp(string, ctx->packet,
strlen(string)) != 0
|| strcspn(string, "\n")
!= strcspn(ctx->packet, "\n")) {
state = P_BEGIN;
break;
}
state = P_STATUS;
continue;
case P_STATUS:
if (strcasecmp(string, "SUCCESS") == 0) {
status = 0;
} else if (strcasecmp(string, "END") == 0) {
logprintf(LIRC_NOTICE,
"lirc_command_run: status:END");
return 0;
} else if (strcasecmp(string, "ERROR") == 0) {
logprintf(LIRC_WARNING,
"%s: command failed: %s",
prog, ctx->packet);
status = EIO;
} else {
goto bad_packet;
}
state = P_DATA;
break;
case P_DATA:
if (strcasecmp(string, "END") == 0) {
logprintf(LIRC_NOTICE,
"lirc_command_run: data:END, status:%d",
status);
return status;
} else if (strcasecmp(string, "DATA") == 0) {
state = P_N;
break;
}
logprintf(LIRC_DEBUG,
"data: bad packet: %s\n",
string);
goto bad_packet;
case P_N:
errno = 0;
data_n = (uint32_t)strtoul(string, &endptr, 0);
if (!*string || *endptr)
goto bad_packet;
if (data_n == 0)
state = P_END;
else
state = P_DATA_N;
break;
case P_DATA_N:
if (n == 0) {
if (ctx->reply_to_stdout)
puts("");
else
strcpy(ctx->reply, "");
}
if (ctx->reply_to_stdout) {
chk_write(STDOUT_FILENO, string, strlen(string),
"reply (1)");
chk_write(STDOUT_FILENO, "\n", 1, "reply (2)");
} else {
strncpy(ctx->reply,
string,
PACKET_SIZE - strlen(ctx->reply));
}
n++;
if (n == data_n)
state = P_END;
break;
case P_END:
if (strcasecmp(string, "END") == 0) {
logprintf(LIRC_NOTICE,
"lirc_command_run: status:END, status:%d",
status);
return status;
}
goto bad_packet;
}
}
bad_packet:
logprintf(LIRC_WARNING, "%s: bad return packet\n", prog);
logprintf(LIRC_DEBUG, "State %d: bad packet: %s\n", status, string);
return EPROTO;
}
static void lirc_printf(const char* format_str, ...)
{
va_list ap;
if (!lirc_verbose)
return;
va_start(ap, format_str);
vfprintf(stderr, format_str, ap);
va_end(ap);
}
static void lirc_perror(const char* s)
{
if (!lirc_verbose)
return;
perror(s);
}
int lirc_init(const char* prog, int verbose)
{
if (prog == NULL || lirc_prog != NULL)
return -1;
lirc_lircd = lirc_get_local_socket(NULL, !verbose);
if (lirc_lircd >= 0) {
lirc_verbose = verbose;
lirc_prog = strdup(prog);
if (lirc_prog == NULL) {
lirc_printf("%s: out of memory\n", prog);
return -1;
}
return lirc_lircd;
}
lirc_printf("%s: could not open socket: %s\n",
lirc_prog,
strerror(-lirc_lircd));
return -1;
}
int lirc_deinit(void)
{
int r = 0;
if (lirc_prog != NULL) {
free(lirc_prog);
lirc_prog = NULL;
}
if (lirc_buffer != NULL) {
free(lirc_buffer);
lirc_buffer = NULL;
}
if (lirc_lircd != -1) {
r = close(lirc_lircd);
lirc_lircd = -1;
}
return r == 0 ? 1 : 0;
}
void lirc_set_verbose(int v) { lirc_verbose = v; }
static int lirc_readline(char** line, FILE* f)
{
char* newline;
char* ret;
char* enlargeline;
int len;
newline = (char*)malloc(LIRC_READ + 1);
if (newline == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
return -1;
}
len = 0;
while (1) {
ret = fgets(newline + len, LIRC_READ + 1, f);
if (ret == NULL) {
if (feof(f) && len > 0) {
*line = newline;
} else {
free(newline);
*line = NULL;
}
return 0;
}
len = strlen(newline);
if (newline[len - 1] == '\n') {
newline[len - 1] = 0;
*line = newline;
return 0;
}
enlargeline = (char*)realloc(newline, len + 1 + LIRC_READ);
if (enlargeline == NULL) {
free(newline);
lirc_printf("%s: out of memory\n", lirc_prog);
return -1;
}
newline = enlargeline;
}
}
static char* lirc_trim(char* s)
{
int len;
while (s[0] == ' ' || s[0] == '\t')
s++;
len = strlen(s);
while (len > 0) {
len--;
if (s[len] == ' ' || s[len] == '\t')
s[len] = 0;
else
break;
}
return s;
}
/* parse standard C escape sequences + \@,\A-\Z is ^@,^A-^Z */
static char lirc_parse_escape(char** s, const char* name, int line)
{
char c;
unsigned int i, overflow, count;
int digits_found, digit;
c = **s;
(*s)++;
switch (c) {
case 'a':
return '\a';
case 'b':
return '\b';
case 'e':
#if 0
case 'E': /* this should become ^E */
#endif
return 033;
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case '\n':
return 0;
case 0:
(*s)--;
return 0;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
i = c - '0';
count = 0;
while (++count < 3) {
c = *(*s)++;
if (c >= '0' && c <= '7') {
i = (i << 3) + c - '0';
} else {
(*s)--;
break;
}
}
if (i > (1 << CHAR_BIT) - 1) {
i &= (1 << CHAR_BIT) - 1;
lirc_printf(
"%s: octal escape sequence out of range in %s:%d\n",
lirc_prog, name, line);
}
return (char)i;
case 'x':
{
i = 0;
overflow = 0;
digits_found = 0;
for (;; ) {
c = *(*s)++;
if (c >= '0' && c <= '9') {
digit = c - '0';
} else if (c >= 'a' && c <= 'f') {
digit = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
digit = c - 'A' + 10;
} else {
(*s)--;
break;
}
overflow |= i ^ (i << 4 >> 4);
i = (i << 4) + digit;
digits_found = 1;
}
if (!digits_found)
lirc_printf("%s: \\x used with no "
"following hex digits in %s:%d\n",
lirc_prog, name, line);
if (overflow || i > (1 << CHAR_BIT) - 1) {
i &= (1 << CHAR_BIT) - 1;
lirc_printf("%s: hex escape sequence out "
"of range in %s:%d\n", lirc_prog, name,
line);
}
return (char)i;
}
default:
if (c >= '@' && c <= 'Z')
return c - '@';
return c;
}
}
static void lirc_parse_string(char* s, const char* name, int line)
{
char* t;
t = s;
while (*s != 0) {
if (*s == '\\') {
s++;
*t = lirc_parse_escape(&s, name, line);
t++;
} else {
*t = *s;
s++;
t++;
}
}
*t = 0;
}
static void lirc_parse_include(char* s, const char* name, int line)
{
char last;
size_t len;
len = strlen(s);
if (len < 2)
return;
last = s[len - 1];
if (*s != '"' && *s != '<')
return;
if (*s == '"' && last != '"')
return;
else if (*s == '<' && last != '>')
return;
s[len - 1] = 0;
memmove(s, s + 1, len - 2 + 1); /* terminating 0 is copied */
}
int lirc_mode(char* token, char* token2, char** mode,
struct lirc_config_entry** new_config,
struct lirc_config_entry** first_config,
struct lirc_config_entry** last_config,
int (check) (char* s),
const char* name,
int line)
{
struct lirc_config_entry* new_entry;
new_entry = *new_config;
if (strcasecmp(token, "begin") == 0) {
if (token2 == NULL) {
if (new_entry == NULL) {
new_entry = (struct lirc_config_entry*)
malloc(sizeof(struct lirc_config_entry));
if (new_entry == NULL) {
lirc_printf("%s: out of memory\n",
lirc_prog);
return -1;
}
new_entry->prog = NULL;
new_entry->code = NULL;
new_entry->rep_delay = 0;
new_entry->ign_first_events = 0;
new_entry->rep = 0;
new_entry->config = NULL;
new_entry->change_mode = NULL;
new_entry->flags = none;
new_entry->mode = NULL;
new_entry->next_config = NULL;
new_entry->next_code = NULL;
new_entry->next = NULL;
*new_config = new_entry;
} else {
lirc_printf("%s: bad file format, %s:%d\n",
lirc_prog, name, line);
return -1;
}
} else {
if (new_entry == NULL && *mode == NULL) {
*mode = strdup(token2);
if (*mode == NULL)
return -1;
} else {
lirc_printf("%s: bad file format, %s:%d\n",
lirc_prog, name, line);
return -1;
}
}
} else if (strcasecmp(token, "end") == 0) {
if (token2 == NULL) {
if (new_entry != NULL) {
#if 0
if (new_entry->prog == NULL) {
lirc_printf(
"%s: prog missing in config before line %d\n", lirc_prog,
line);
lirc_freeconfigentries(new_entry);
*new_config = NULL;
return -1;
}
if (strcasecmp(new_entry->prog,
lirc_prog) != 0) {
lirc_freeconfigentries(new_entry);
*new_config = NULL;
return 0;
}
#endif
new_entry->next_code = new_entry->code;
new_entry->next_config = new_entry->config;
if (*last_config == NULL) {
*first_config = new_entry;
*last_config = new_entry;
} else {
(*last_config)->next = new_entry;
*last_config = new_entry;
}
*new_config = NULL;
if (*mode != NULL) {
new_entry->mode = strdup(*mode);
if (new_entry->mode == NULL) {
lirc_printf(
"%s: out of memory\n",
lirc_prog);
return -1;
}
}
if (check != NULL &&
new_entry->prog != NULL &&
strcasecmp(new_entry->prog,
lirc_prog) == 0) {
struct lirc_list* list;
list = new_entry->config;
while (list != NULL) {
if (check(list->string) == -1)
return -1;
list = list->next;
}
}
if (new_entry->rep_delay == 0 &&
new_entry->rep > 0)
new_entry->rep_delay = new_entry->rep -
1;
} else {
lirc_printf(
"%s: %s:%d: 'end' without 'begin'\n",
lirc_prog, name, line);
return -1;
}
} else {
if (*mode != NULL) {
if (new_entry != NULL) {
lirc_printf(
"%s: %s:%d: missing 'end' token\n",
lirc_prog, name, line);
return -1;
}
if (strcasecmp(*mode, token2) == 0) {
free(*mode);
*mode = NULL;
} else {
lirc_printf("%s: \"%s\" doesn't "
"match mode \"%s\"\n",
lirc_prog, token2, *mode);
return -1;
}
} else {
lirc_printf(
"%s: %s:%d: 'end %s' without 'begin'\n",
lirc_prog, name, line, token2);
return -1;
}
}
} else {
lirc_printf("%s: unknown token \"%s\" in %s:%d ignored\n",
lirc_prog, token, name, line);
}
return 0;
}
unsigned int lirc_flags(char* string)
{
char* s;
unsigned int flags;
flags = none;
s = strtok(string, " \t|");
while (s) {
if (strcasecmp(s, "once") == 0)
flags |= once;
else if (strcasecmp(s, "quit") == 0)
flags |= quit;
else if (strcasecmp(s, "mode") == 0)
flags |= mode;
else if (strcasecmp(s, "startup_mode") == 0)
flags |= startup_mode;
else if (strcasecmp(s, "toggle_reset") == 0)
flags |= toggle_reset;
else
lirc_printf("%s: unknown flag \"%s\"\n", lirc_prog, s);
s = strtok(NULL, " \t");
}
return flags;
}
static char* get_homepath(void)
{
char* home;
char* filename;
filename = malloc(MAXPATHLEN);
if (filename == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
return NULL;
}
home = getenv("HOME");
home = home == NULL ? "/" : home;
strncpy(filename, home, MAXPATHLEN);
if (filename[strlen(filename) - 1] == '/')
filename[strlen(filename) - 1] = '\0';
return filename;
}
static char* get_freedesktop_path(void)
{
char* path;
if (getenv("XDG_CONFIG_HOME") != NULL) {
path = malloc(MAXPATHLEN);
strncpy(path, getenv("XDG_CONFIG_HOME"), MAXPATHLEN);
strncat(path, "/", MAXPATHLEN - strlen(path));
strncat(path, CFG_LIRCRC, MAXPATHLEN - strlen(path));
} else {
path = get_homepath();
if (path == NULL)
return NULL;
strncat(path, "/.config/lircrc", MAXPATHLEN - strlen(path) - 1);
}
if (access(path, R_OK) != 0)
path[0] = '\0';
return path;
}
static char* lirc_getfilename(const char* file, const char* current_file)
{
char* filename;
if (file == NULL) {
filename = get_freedesktop_path();
if (filename == NULL) {
return NULL;
} else if (strlen(filename) == 0) {
free(filename);
filename = get_homepath();
if (filename == NULL)
return NULL;
strcat(filename, "/" LIRCRC_USER_FILE);
}
filename = realloc(filename, strlen(filename) + 1);
} else if (strncmp(file, "~/", 2) == 0) {
filename = get_homepath();
if (filename == NULL)
return NULL;
strcat(filename, file + 1);
filename = realloc(filename, strlen(filename) + 1);
} else if (file[0] == '/' || current_file == NULL) {
/* absolute path or root */
filename = strdup(file);
if (filename == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
return NULL;
}
} else {
/* get path from parent filename */
int pathlen = strlen(current_file);
while (pathlen > 0 && current_file[pathlen - 1] != '/')
pathlen--;
filename = (char*)malloc(pathlen + strlen(file) + 1);
if (filename == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
return NULL;
}
memcpy(filename, current_file, pathlen);
filename[pathlen] = 0;
strcat(filename, file);
}
return filename;
}
static FILE* lirc_open(const char* file,
const char* current_file,
char** full_name)
{
FILE* fin;
char* filename;
filename = lirc_getfilename(file, current_file);
if (filename == NULL)
return NULL;
fin = fopen(filename, "r");
if (fin == NULL && (file != NULL || errno != ENOENT)) {
lirc_printf("%s: could not open config file %s\n", lirc_prog,
filename);
lirc_perror(lirc_prog);
} else if (fin == NULL) {
const char* root_file = LIRCRC_ROOT_FILE;
fin = fopen(root_file, "r");
if (fin == NULL && errno == ENOENT) {
int save_errno = errno;
root_file = LIRCRC_OLD_ROOT_FILE;
fin = fopen(root_file, "r");
errno = save_errno;
}
if (fin == NULL && errno != ENOENT) {
lirc_printf("%s: could not open config file %s\n",
lirc_prog, LIRCRC_ROOT_FILE);
lirc_perror(lirc_prog);
} else if (fin == NULL) {
lirc_printf("%s: could not open config files "
"%s and %s\n", lirc_prog, filename,
LIRCRC_ROOT_FILE);
lirc_perror(lirc_prog);
} else {
free(filename);
filename = strdup(root_file);
if (filename == NULL) {
fclose(fin);
lirc_printf("%s: out of memory\n", lirc_prog);
return NULL;
}
}
}
if (full_name && fin != NULL)
*full_name = filename;
else
free(filename);
return fin;
}
static struct filestack_t* stack_push(struct filestack_t* parent)
{
struct filestack_t* entry;
entry = malloc(sizeof(struct filestack_t));
if (entry == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
return NULL;
}
entry->file = NULL;
entry->name = NULL;
entry->line = 0;
entry->parent = parent;
return entry;
}
static struct filestack_t* stack_pop(struct filestack_t* entry)
{
struct filestack_t* parent = NULL;
if (entry) {
parent = entry->parent;
if (entry->name)
free(entry->name);
free(entry);
}
return parent;
}
static void stack_free(struct filestack_t* entry)
{
while (entry)
entry = stack_pop(entry);
}
static char* lirc_startupmode(struct lirc_config_entry* first)
{
struct lirc_config_entry* scan;
char* startupmode;
startupmode = NULL;
scan = first;
/* Set a startup mode based on flags=startup_mode */
while (scan != NULL) {
if (scan->flags & startup_mode) {
if (scan->change_mode != NULL) {
startupmode = scan->change_mode;
/* Remove the startup mode or it confuses lirc mode system */
scan->change_mode = NULL;
break;
}
lirc_printf("%s: startup_mode flags requires 'mode ='\n", lirc_prog);
}
scan = scan->next;
}
/* Set a default mode if we find a mode = client app name */
if (startupmode == NULL) {
scan = first;
while (scan != NULL) {
if (scan->mode != NULL
&& lirc_prog != NULL
&& strcasecmp(lirc_prog, scan->mode) == 0) {
startupmode = lirc_prog;
break;
}
scan = scan->next;
}
}
if (startupmode == NULL)
return NULL;
scan = first;
while (scan != NULL) {
if (scan->change_mode != NULL
&& scan->flags & once
&& strcasecmp(startupmode, scan->change_mode) == 0)
scan->flags |= ecno;
scan = scan->next;
}
return startupmode;
}
static void lirc_freeconfigentries(struct lirc_config_entry* first)
{
struct lirc_config_entry* c;
struct lirc_config_entry* config_temp;
struct lirc_list* list;
struct lirc_list* list_temp;
struct lirc_code* code;
struct lirc_code* code_temp;
c = first;
while (c != NULL) {
if (c->prog)
free(c->prog);
if (c->change_mode)
free(c->change_mode);
if (c->mode)
free(c->mode);
code = c->code;
while (code != NULL) {
if (code->remote != NULL && code->remote != LIRC_ALL)
free(code->remote);
if (code->button != NULL && code->button != LIRC_ALL)
free(code->button);
code_temp = code->next;
free(code);
code = code_temp;
}
list = c->config;
while (list != NULL) {
if (list->string)
free(list->string);
list_temp = list->next;
free(list);
list = list_temp;
}
config_temp = c->next;
free(c);
c = config_temp;
}
}
static void
parse_shebang(char* line, int depth, const char* path, char* buff, size_t size)
{
char* token;
char my_path[128];
const char* const SHEBANG_MSG =
"Warning: Use of deprecated lircrc shebang."
" Use lircrc_class instead.\n";
token = strtok(line, "#! ");
buff[0] = '\0';
if (depth > 1) {
lirc_printf("Warning: ignoring shebang in included file.");
return;
}
if (strcmp(token, "lircrc") == 0) {
strncpy(my_path, path, sizeof(my_path) - 1);
strncat(buff, basename(my_path), size - 1);
lirc_printf(SHEBANG_MSG);
} else {
lirc_printf("Warning: bad shebang (ignored)");
}
}
static int lirc_readconfig_only_internal(const char* file,
struct lirc_config** config,
int (check)(char* s),
char** full_name)
{
const char* const INCLUDED_LIRCRC_CLASS =
"Warning: lirc_class in included file (ignored)";
char* string;
char* eq;
char* token;
char* token2;
char* token3;
struct filestack_t* filestack;
struct filestack_t* stack_tmp;
int open_files;
char lircrc_class[128] = { '\0' };
struct lirc_config_entry* new_entry;
struct lirc_config_entry* first;
struct lirc_config_entry* last;
char* mode;
char* remote;
int ret = 0;
int firstline = 1;
char* save_full_name = NULL;
filestack = stack_push(NULL);
if (filestack == NULL)
return -1;
filestack->file = lirc_open(file, NULL, &(filestack->name));
if (filestack->file == NULL) {
stack_free(filestack);
return -1;
}
filestack->line = 0;
open_files = 1;
first = new_entry = last = NULL;
mode = NULL;
remote = LIRC_ALL;
while (filestack) {
ret = lirc_readline(&string, filestack->file);
if (ret == -1 || string == NULL) {
fclose(filestack->file);
if (open_files == 1 && full_name != NULL) {
save_full_name = filestack->name;
filestack->name = NULL;
}
filestack = stack_pop(filestack);
open_files--;
continue;
}
/* check for sha-bang */
if (firstline) {
firstline = 0;
if (strncmp(string, "#!", 2) == 0) {
parse_shebang(string,
open_files,
file,
lircrc_class,
sizeof(lircrc_class));
}
}
filestack->line++;
eq = strchr(string, '=');
if (eq == NULL) {
token = strtok(string, " \t");
if (token == NULL) {
/* ignore empty line */
} else if (token[0] == '#') {
/* ignore comment */
} else if (strcasecmp(token, "lircrc_class") == 0) {
token2 = lirc_trim(strtok(NULL, ""));
if (strlen(token2) == 0) {
lirc_printf(
"Warning: no lircrc_class");
} else if (open_files == 1) {
strncpy(lircrc_class,
token2,
sizeof(lircrc_class) - 1);
} else {
lirc_printf(INCLUDED_LIRCRC_CLASS);
}
} else if (strcasecmp(token, "include") == 0) {
if (open_files >= MAX_INCLUDES) {
lirc_printf("%s: too many files "
"included at %s:%d\n",
lirc_prog, filestack->name,
filestack->line);
ret = -1;
} else {
token2 = strtok(NULL, "");
token2 = lirc_trim(token2);
lirc_parse_include(token2,
filestack->name,
filestack->line);
stack_tmp = stack_push(filestack);
if (stack_tmp == NULL) {
ret = -1;
} else {
stack_tmp->file =
lirc_open(token2,
filestack->name,
&(stack_tmp->
name));
stack_tmp->line = 0;
if (stack_tmp->file) {
open_files++;
filestack = stack_tmp;
} else {
stack_pop(stack_tmp);
ret = -1;
}
}
}
} else {
token2 = strtok(NULL, " \t");
if (token2)
token3 = strtok(NULL, " \t");
if (token2 != NULL && token3 != NULL) {
lirc_printf("%s: unexpected token in line %s:%d\n",
lirc_prog, filestack->name, filestack->line);
} else {
ret = lirc_mode(token, token2, &mode,
&new_entry, &first,
&last,
check, filestack->name,
filestack->line);
if (ret == 0) {
if (remote != LIRC_ALL)
free(remote);
remote = LIRC_ALL;
} else {
if (mode != NULL) {
free(mode);
mode = NULL;
}
if (new_entry != NULL) {
lirc_freeconfigentries(
new_entry);
new_entry = NULL;
}
}
}
}
} else {
eq[0] = 0;
token = lirc_trim(string);
token2 = lirc_trim(eq + 1);
if (token[0] == '#') {
/* ignore comment */
} else if (new_entry == NULL) {
lirc_printf("%s: bad file format, %s:%d\n",
lirc_prog, filestack->name,
filestack->line);
ret = -1;
} else {
token2 = strdup(token2);
if (token2 == NULL) {
lirc_printf("%s: out of memory\n",
lirc_prog);
ret = -1;
} else if (strcasecmp(token, "prog") == 0) {
if (new_entry->prog != NULL)
free(new_entry->prog);
new_entry->prog = token2;
} else if (strcasecmp(token, "remote") == 0) {
if (remote != LIRC_ALL)
free(remote);
if (strcasecmp("*", token2) == 0) {
remote = LIRC_ALL;
free(token2);
} else {
remote = token2;
}
} else if (strcasecmp(token, "button") == 0) {
struct lirc_code* code;
code = (struct lirc_code*)
malloc(sizeof(struct lirc_code));
if (code == NULL) {
free(token2);
lirc_printf(
"%s: out of memory\n",
lirc_prog);
ret = -1;
} else {
code->remote = remote;
if (strcasecmp("*",
token2) == 0) {
code->button = LIRC_ALL;
free(token2);
} else {
code->button = token2;
}
code->next = NULL;
if (new_entry->code == NULL)
new_entry->code = code;
else
new_entry->next_code->
next = code;
new_entry->next_code = code;
if (remote != LIRC_ALL) {
remote = strdup(remote);
if (remote == NULL) {
lirc_printf(
"%s: out of memory\n",
lirc_prog);
ret = -1;
}
}
}
} else if (strcasecmp(token, "delay") == 0) {
char* end;
errno = ERANGE + 1;
new_entry->rep_delay = strtoul(token2,
&end, 0);
if ((new_entry->rep_delay ==
ULONG_MAX && errno == ERANGE)
|| end[0] != 0 || strlen(token2) ==
0)
lirc_printf("%s: \"%s\" not"
" a valid number for delay\n", lirc_prog,
token2);
free(token2);
} else if (strcasecmp(token, "ignore_first_events") == 0) {
char* end;
errno = ERANGE + 1;
new_entry->ign_first_events = strtoul(
token2, &end, 0);
if ((new_entry->ign_first_events ==
ULONG_MAX && errno == ERANGE)
|| end[0] != 0 || strlen(token2) ==
0)
lirc_printf("%s: \"%s\" not"
" a valid number for ignore_first_events\n",
lirc_prog, token2);
free(token2);
} else if (strcasecmp(token, "repeat") == 0) {
char* end;
errno = ERANGE + 1;
new_entry->rep =
strtoul(token2, &end, 0);
if ((new_entry->rep == ULONG_MAX &&
errno == ERANGE)
|| end[0] != 0 || strlen(token2) ==
0)
lirc_printf("%s: \"%s\" not"
" a valid number for repeat\n", lirc_prog,
token2);
free(token2);
} else if (strcasecmp(token, "config") == 0) {
struct lirc_list* new_list;
new_list = (struct lirc_list*)
malloc(sizeof(struct lirc_list));
if (new_list == NULL) {
free(token2);
lirc_printf(
"%s: out of memory\n",
lirc_prog);
ret = -1;
} else {
lirc_parse_string(token2,
filestack->name,
filestack->line);
new_list->string = token2;
new_list->next = NULL;
if (new_entry->config == NULL)
new_entry->config =
new_list;
else
new_entry->next_config->
next = new_list;
new_entry->next_config =
new_list;
}
} else if (strcasecmp(token, "mode") == 0) {
if (new_entry->change_mode != NULL)
free(new_entry->change_mode);
new_entry->change_mode = token2;
} else if (strcasecmp(token, "flags") == 0) {
new_entry->flags = lirc_flags(token2);
free(token2);
} else {
free(token2);
lirc_printf(
"%s: unknown token \"%s\" in %s:%d ignored\n",
lirc_prog, token, filestack->name,
filestack->line);
}
}
}
free(string);
if (ret == -1)
break;
}
if (remote != LIRC_ALL)
free(remote);
if (new_entry != NULL) {
if (ret == 0) {
ret = lirc_mode("end", NULL, &mode, &new_entry, &first,
&last, check, "", 0);
lirc_printf(
"%s: warning: end token missing at end of file\n",
lirc_prog);
} else {
lirc_freeconfigentries(new_entry);
new_entry = NULL;
}
}
if (mode != NULL) {
if (ret == 0)
lirc_printf(
"%s: warning: no end token found for mode \"%s\"\n", lirc_prog,
mode);
free(mode);
}
if (ret == 0) {
char* startupmode;
*config = (struct lirc_config*)
malloc(sizeof(struct lirc_config));
if (*config == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
lirc_freeconfigentries(first);
return -1;
}
(*config)->first = first;
(*config)->next = first;
startupmode = lirc_startupmode((*config)->first);
(*config)->current_mode =
startupmode ? strdup(startupmode) : NULL;
if (lircrc_class[0] != '\0')
(*config)->lircrc_class = strdup(lircrc_class);
else
(*config)->lircrc_class = NULL;
(*config)->sockfd = -1;
if (full_name != NULL) {
*full_name = save_full_name;
save_full_name = NULL;
}
} else {
*config = NULL;
lirc_freeconfigentries(first);
}
if (filestack)
stack_free(filestack);
if (save_full_name)
free(save_full_name);
return ret;
}
int lirc_identify(int sockfd)
{
lirc_cmd_ctx cmd;
int ret;
ret = lirc_command_init(&cmd, "IDENT %s\n", lirc_prog);
if (ret != 0)
return ret;
do
ret = lirc_command_run(&cmd, sockfd);
while (ret == EAGAIN || ret == EWOULDBLOCK);
return ret == 0 ? LIRC_RET_SUCCESS : -1;
}
int lirc_readconfig(const char* file,
struct lirc_config** config,
int (check)(char* s))
{
struct sockaddr_un addr;
int sockfd = -1;
char* filename;
char command[128];
int ret;
filename = NULL;
if (lirc_readconfig_only_internal(file, config, check, &filename) == -1)
return -1;
if ((*config)->lircrc_class == NULL)
goto lirc_readconfig_compat;
/* connect to lircrcd */
addr.sun_family = AF_UNIX;
if (lirc_getsocketname((*config)->lircrc_class,
addr.sun_path,
sizeof(addr.sun_path)) > sizeof(addr.sun_path)) {
lirc_printf("%s: WARNING: file name too long\n", lirc_prog);
goto lirc_readconfig_compat;
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
lirc_printf("%s: WARNING: could not open socket\n", lirc_prog);
lirc_perror(lirc_prog);
goto lirc_readconfig_compat;
}
if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != -1) {
(*config)->sockfd = sockfd;
free(filename);
/* tell daemon lirc_prog */
if (lirc_identify(sockfd) == LIRC_RET_SUCCESS)
/* we're connected */
return 0;
close(sockfd);
lirc_freeconfig(*config);
return -1;
}
close(sockfd);
sockfd = -1;
/* launch lircrcd */
snprintf(command, sizeof(command),
"lircrcd %s", (*config)->lircrc_class);
ret = system(command);
if (ret == -1 || WEXITSTATUS(ret) != EXIT_SUCCESS)
goto lirc_readconfig_compat;
free(filename);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
lirc_printf("%s: WARNING: could not open socket\n", lirc_prog);
lirc_perror(lirc_prog);
goto lirc_readconfig_compat;
}
if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != -1) {
if (lirc_identify(sockfd) == LIRC_RET_SUCCESS) {
(*config)->sockfd = sockfd;
return 0;
}
}
close(sockfd);
lirc_freeconfig(*config);
return -1;
lirc_readconfig_compat:
/* compat fallback */
if (sockfd != -1)
close(sockfd);
return 0;
}
int lirc_readconfig_only(const char* file,
struct lirc_config** config,
int (check) (char* s))
{
return lirc_readconfig_only_internal(file, config, check, NULL);
}
void lirc_freeconfig(struct lirc_config* config)
{
if (config != NULL) {
if (config->sockfd != -1) {
(void)close(config->sockfd);
config->sockfd = -1;
}
if (config->lircrc_class != NULL)
free(config->lircrc_class);
lirc_freeconfigentries(config->first);
free(config->current_mode);
free(config);
}
}
static void lirc_clearmode(struct lirc_config* config)
{
struct lirc_config_entry* scan;
if (config->current_mode == NULL)
return;
scan = config->first;
while (scan != NULL) {
if (scan->change_mode != NULL)
if (strcasecmp(scan->change_mode,
config->current_mode) == 0)
scan->flags &= ~ecno;
scan = scan->next;
}
free(config->current_mode);
config->current_mode = NULL;
}
static char* lirc_execute(struct lirc_config* config,
struct lirc_config_entry* scan)
{
char* s;
int do_once = 1;
if (scan->flags & mode)
lirc_clearmode(config);
if (scan->change_mode != NULL) {
free(config->current_mode);
config->current_mode = strdup(scan->change_mode);
if (scan->flags & once) {
if (scan->flags & ecno)
do_once = 0;
else
scan->flags |= ecno;
}
}
if (scan->next_config != NULL
&& scan->prog != NULL
&& (lirc_prog == NULL || strcasecmp(scan->prog, lirc_prog) == 0)
&& do_once == 1) {
s = scan->next_config->string;
scan->next_config = scan->next_config->next;
if (scan->next_config == NULL)
scan->next_config = scan->config;
return s;
}
return NULL;
}
static int rep_filter(struct lirc_config_entry* scan, int rep)
{
int delay_start, rep_delay;
if (scan->ign_first_events) {
if (scan->rep_delay && rep == 0) /* warn user only once */
lirc_printf(
"%s: ignoring \"delay\" because \"ignore_first_events\" is also set\n",
lirc_prog);
rep_delay = scan->ign_first_events;
delay_start = 0;
} else {
rep_delay = scan->rep_delay;
delay_start = 1;
}
/* handle event before delay_start */
if (rep < delay_start)
return 1;
/* special case: 1 event after delay when repeat is not set */
if (scan->rep == 0 && rep_delay > 0 && rep == rep_delay + delay_start)
return 1;
/* handle repeat */
if (scan->rep > 0 && rep >= rep_delay + delay_start) {
rep -= rep_delay + delay_start;
return (rep % scan->rep) == 0;
}
return 0;
}
static int lirc_iscode(struct lirc_config_entry* scan,
char* remote,
char* button,
int rep)
{
struct lirc_code* codes;
/* no remote/button specified */
if (scan->code == NULL)
return rep_filter(scan, rep);
/* remote/button match? */
if (scan->next_code->remote == LIRC_ALL
|| strcasecmp(scan->next_code->remote, remote) == 0) {
if (scan->next_code->button == LIRC_ALL
|| strcasecmp(scan->next_code->button, button) == 0) {
int iscode = 0;
/* button sequence? */
if (scan->code->next == NULL || rep == 0) {
scan->next_code = scan->next_code->next;
if (scan->code->next != NULL)
iscode = 1;
}
/* sequence completed? */
if (scan->next_code == NULL) {
scan->next_code = scan->code;
if (scan->code->next != NULL ||
rep_filter(scan, rep))
iscode = 2;
}
return iscode;
}
}
if (rep != 0)
return 0;
/* handle toggle_reset */
if (scan->flags & toggle_reset)
scan->next_config = scan->config;
codes = scan->code;
if (codes == scan->next_code)
return 0;
codes = codes->next;
/* rebase code sequence */
while (codes != scan->next_code->next) {
struct lirc_code* prev;
struct lirc_code* next;
int flag = 1;
prev = scan->code;
next = codes;
while (next != scan->next_code) {
if (prev->remote == LIRC_ALL
|| strcasecmp(prev->remote, next->remote) == 0) {
if (prev->button == LIRC_ALL
|| strcasecmp(prev->button,
next->button) == 0) {
prev = prev->next;
next = next->next;
} else {
flag = 0;
break;
}
} else {
flag = 0;
break;
}
}
if (flag == 1) {
if (prev->remote == LIRC_ALL
|| strcasecmp(prev->remote, remote) == 0) {
if (prev->button == LIRC_ALL
|| strcasecmp(prev->button, button) == 0) {
if (rep == 0) {
scan->next_code = prev->next;
return 0;
}
}
}
}
codes = codes->next;
}
scan->next_code = scan->code;
return 0;
}
char* lirc_ir2char(struct lirc_config* config, char* code)
{
static int warning = 1;
char* string;
if (warning) {
fprintf(stderr, "%s: warning: lirc_ir2char() is obsolete\n",
lirc_prog);
warning = 0;
}
if (lirc_code2char(config, code, &string) == -1)
return NULL;
return string;
}
static int lirc_code2char_internal(struct lirc_config* config,
char* code,
char** string,
char** prog)
{
int rep;
char* backup;
char* remote;
char* button;
char* s = NULL;
struct lirc_config_entry* scan;
int exec_level;
int quit_happened;
*string = NULL;
if (sscanf(code, "%*x %x %*s %*s\n", &rep) == 1) {
backup = strdup(code);
if (backup == NULL)
return -1;
strtok(backup, " ");
strtok(NULL, " ");
button = strtok(NULL, " ");
remote = strtok(NULL, "\n");
if (button == NULL || remote == NULL) {
free(backup);
return 0;
}
scan = config->next;
quit_happened = 0;
while (scan != NULL) {
exec_level = lirc_iscode(scan, remote, button, rep);
if (exec_level > 0 &&
(scan->mode == NULL ||
(scan->mode != NULL &&
config->current_mode != NULL &&
strcasecmp(scan->mode,
config->current_mode) == 0)) &&
quit_happened == 0) {
if (exec_level > 1) {
s = lirc_execute(config, scan);
if (s != NULL && prog != NULL)
*prog = scan->prog;
} else {
s = NULL;
}
if (scan->flags & quit) {
quit_happened = 1;
config->next = NULL;
scan = scan->next;
continue;
} else if (s != NULL) {
config->next = scan->next;
break;
}
}
scan = scan->next;
}
free(backup);
if (s != NULL) {
*string = s;
return 0;
}
}
config->next = config->first;
return 0;
}
int lirc_code2char(struct lirc_config* config, char* code, char** string)
{
lirc_cmd_ctx cmd;
static char static_buff[PACKET_SIZE];
int ret;
char* my_code;
char* pos;
my_code = strdup(code);
pos = rindex(my_code, '\n');
if (pos != NULL)
*pos = '\0';
ret = lirc_command_init(&cmd, "CODE %s\n", my_code);
free(my_code);
if (ret != 0)
return -1;
if (config->sockfd != -1) {
do
ret = lirc_command_run(&cmd, config->sockfd);
while (ret == EAGAIN || ret == EWOULDBLOCK);
if (ret == 0) {
strncpy(static_buff, cmd.reply, PACKET_SIZE);
*string = static_buff;
}
return ret == 0 ? 0 : -1;
}
return lirc_code2char_internal(config, code, string, NULL);
}
int lirc_code2charprog(struct lirc_config* config,
char* code,
char** string,
char** prog)
{
char* backup;
int ret;
backup = lirc_prog;
lirc_prog = NULL;
ret = lirc_code2char_internal(config, code, string, prog);
lirc_prog = backup;
return ret;
}
char* lirc_nextir(void)
{
static int warning = 1;
char* code;
int ret;
if (warning) {
fprintf(stderr, "%s: warning: lirc_nextir() is obsolete\n",
lirc_prog);
warning = 0;
}
ret = lirc_nextcode(&code);
if (ret == -1)
return NULL;
return code;
}
int lirc_nextcode(char** code)
{
static int packet_size = PACKET_SIZE;
static int end_len = 0;
ssize_t len = 0;
char* end;
char c;
*code = NULL;
if (lirc_buffer == NULL) {
lirc_buffer = (char*)malloc(packet_size + 1);
if (lirc_buffer == NULL) {
lirc_printf("%s: out of memory\n", lirc_prog);
return -1;
}
lirc_buffer[0] = 0;
}
while ((end = strchr(lirc_buffer, '\n')) == NULL) {
if (end_len >= packet_size) {
char* new_buffer;
packet_size += PACKET_SIZE;
new_buffer =
(char*)realloc(lirc_buffer, packet_size + 1);
if (new_buffer == NULL)
return -1;
lirc_buffer = new_buffer;
}
len = read(lirc_lircd, lirc_buffer + end_len,
packet_size - end_len);
if (len <= 0) {
if (len == -1 && errno == EAGAIN)
return 0;
else
return -1;
}
end_len += len;
lirc_buffer[end_len] = 0;
/* return if next code not yet available completely */
end = strchr(lirc_buffer, '\n');
if (end == NULL)
return 0;
}
/* copy first line to buffer (code) and move remaining chars to
* lirc_buffers start */
end++;
end_len = strlen(end);
c = end[0];
end[0] = 0;
*code = strdup(lirc_buffer);
end[0] = c;
memmove(lirc_buffer, end, end_len + 1);
if (*code == NULL)
return -1;
return 0;
}
size_t lirc_getsocketname(const char* id, char* buf, size_t size)
{
id = id != NULL ? id : "default";
snprintf(buf, size, VARRUNDIR "/%d-%s-lircrcd.socket", getuid(), id);
return strlen(buf);
}
const char* lirc_getmode(struct lirc_config* config)
{
lirc_cmd_ctx cmd;
static char static_buff[PACKET_SIZE];
int ret;
if (config->sockfd != -1) {
lirc_command_init(&cmd, "GETMODE\n");
do
ret = lirc_command_run(&cmd, config->sockfd);
while (ret == EAGAIN || ret == EWOULDBLOCK);
if (ret == 0) {
strncpy(static_buff, cmd.reply, PACKET_SIZE);
return static_buff;
}
return NULL;
}
return config->current_mode;
}
const char* lirc_setmode(struct lirc_config* config, const char* mode)
{
lirc_cmd_ctx cmd;
int r;
static char static_buff[PACKET_SIZE];
if (config->sockfd != -1) {
if (mode != NULL)
r = lirc_command_init(&cmd, "SETMODE %s\n", mode);
else
r = lirc_command_init(&cmd, "SETMODE\n");
if (r != 0)
return NULL;
do
r = lirc_command_run(&cmd, config->sockfd);
while (r == EAGAIN || r == EWOULDBLOCK);
if (r == 0) {
strncpy(static_buff, cmd.reply, PACKET_SIZE);
return static_buff;
}
return NULL;
}
free(config->current_mode);
config->current_mode = mode ? strdup(mode) : NULL;
return config->current_mode;
}
int lirc_send_one(int fd, const char* remote, const char* keysym)
{
int r;
lirc_cmd_ctx command;
r = lirc_command_init(&command, "SEND_ONCE %s %s\n", remote, keysym);
if (r != 0)
return EMSGSIZE;
do
r = lirc_command_run(&command, fd);
while (r == EAGAIN);
return r;
}
int lirc_simulate(int fd,
const char* remote,
const char* keysym,
int scancode,
int repeat)
{
lirc_cmd_ctx cmd;
int r;
r = lirc_command_init(&cmd, "SIMULATE %016x %02x %s %s\n",
scancode, repeat, keysym, remote);
if (r != 0)
return EMSGSIZE;
do
r = lirc_command_run(&cmd, fd);
while (r == EAGAIN);
return r;
}
static int
do_connect(int domain, struct sockaddr* addr, size_t size, int quiet)
{
int fd;
fd = socket(domain, SOCK_STREAM, 0);
if (fd == -1) {
if (!quiet) {
fprintf(stderr, "do_connect: could not open socket\n");
perror("open");
}
return -errno;
}
if (connect(fd, addr, size) == -1) {
if (!quiet) {
fprintf(stderr,
"do_connect: could not connect to socket\n");
perror("connect");
}
return -errno;
}
return fd;
}
int lirc_get_local_socket(const char* path, int quiet)
{
const char* socket_path;
struct sockaddr_un addr_un;
socket_path = path ? path : getenv("LIRC_SOCKET_PATH");
socket_path = socket_path ? socket_path : LIRCD;
if (strlen(socket_path) + 1 > sizeof(addr_un.sun_path)) {
/* path is longer than sockaddr_un.sun_path field (!) */
if (!quiet)
fprintf(stderr, "%s: socket name is too long\n", prog);
return -ENAMETOOLONG;
}
addr_un.sun_family = AF_UNIX;
strcpy(addr_un.sun_path, socket_path);
return do_connect(AF_UNIX,
(struct sockaddr*)&addr_un,
sizeof(addr_un),
quiet);
}
int lirc_get_remote_socket(const char* address, int port, int quiet)
{
struct addrinfo* addrinfos;
struct addrinfo* a;
char service[64];
int r;
snprintf(service, sizeof(service),
"%d", port > 0 ? port : LIRC_INET_PORT);
r = getaddrinfo(address, service, NULL, &addrinfos);
if (r < 0) {
if (!quiet)
fprintf(stderr, "get_remote_socket: host %s unknown\n",
address);
return -EADDRNOTAVAIL;
}
for (a = addrinfos; a != NULL; a = a->ai_next) {
r = do_connect(a->ai_family, a->ai_addr, a->ai_addrlen, quiet);
if (r >= 0)
break;
};
freeaddrinfo(addrinfos);
return r;
}
lirc_send_one
int lirc_send_one(int fd, const char *remote, const char *keysym)
Send keysym using given remote.
Definition lirc_client.c:1995
lirc_get_local_socket
int lirc_get_local_socket(const char *path, int quiet)
Return an opened and connected file descriptor to local lirc socket.
Definition lirc_client.c:2056
lirc_nextir
char * lirc_nextir(void)
Definition lirc_client.c:1861
lirc_command_init
int lirc_command_init(lirc_cmd_ctx *ctx, const char *fmt,...)
Initiate a lirc_cmd_ctx to run a command.
Definition lirc_client.c:110
lirc_setmode
const char * lirc_setmode(struct lirc_config *config, const char *mode)
Set mode defined in lircrc.
Definition lirc_client.c:1967
lirc_deinit
int lirc_deinit(void)
Release resources allocated by lirc_init(), basically disconnect from socket.
Definition lirc_client.c:365
lirc_set_verbose
void lirc_set_verbose(int v)
Dynamically change the verbose level defined by lirc_init().
Definition lirc_client.c:384
lirc_readconfig
int lirc_readconfig(const char *file, struct lirc_config **config, int(check)(char *s))
Parse a lircrc configuration file.
Definition lirc_client.c:1447
lirc_ir2char
char * lirc_ir2char(struct lirc_config *config, char *code)
Definition lirc_client.c:1726
lirc_freeconfig
void lirc_freeconfig(struct lirc_config *config)
Deallocate an object retrieved using lirc_readconfig().
Definition lirc_client.c:1534
lirc_get_remote_socket
int lirc_get_remote_socket(const char *address, int port, int quiet)
Return an opened and connected file descriptor to remote lirc socket.
Definition lirc_client.c:2078
lirc_command_run
int lirc_command_run(lirc_cmd_ctx *ctx, int fd)
Run a command in non-blocking mode.
Definition lirc_client.c:190
lirc_code2char
int lirc_code2char(struct lirc_config *config, char *code, char **string)
Translate a code string to an application string using .lircrc.
Definition lirc_client.c:1813
lirc_readconfig_only
int lirc_readconfig_only(const char *file, struct lirc_config **config, int(check)(char *s))
Parse a lircrc configuration file without connecting to lircrcd.
Definition lirc_client.c:1526
lirc_getmode
const char * lirc_getmode(struct lirc_config *config)
Get mode defined in lircrc.
Definition lirc_client.c:1946
lirc_getsocketname
size_t lirc_getsocketname(const char *id, char *buf, size_t size)
Retrieve default lircrcd socket path.
Definition lirc_client.c:1937
lirc_command_reply_to_stdout
void lirc_command_reply_to_stdout(lirc_cmd_ctx *ctx)
Set command_ctx write_to_stdout flag.
Definition lirc_client.c:127
lirc_simulate
int lirc_simulate(int fd, const char *remote, const char *keysym, int scancode, int repeat)
Send a simulated lirc event.This call might block for some time since it involves communication with ...
Definition lirc_client.c:2010
lirc_nextcode
int lirc_nextcode(char **code)
Get next available code from the lircd daemon.
Definition lirc_client.c:1879
lirc_init
int lirc_init(const char *prog, int verbose)
Initial setup: connect to lircd socket.
Definition lirc_client.c:344
packet_state
packet_state
protocol state.
Definition lirc_client.c:76
lirc_client.h
3-rd party application interface.
LIRCRC_OLD_ROOT_FILE
#define LIRCRC_OLD_ROOT_FILE
Compatibility: Old system-wide lircrc path.
Definition lirc_config.h:57
LIRC_INET_PORT
#define LIRC_INET_PORT
default port number for UDP driver
Definition lirc_config.h:27
LIRCRC_USER_FILE
#define LIRCRC_USER_FILE
User lircrc file name.
Definition lirc_config.h:51
CFG_LIRCRC
#define CFG_LIRCRC
config file names - beneath $HOME or SYSCONFDIR
Definition lirc_config.h:21
LIRCD
#define LIRCD
Complete lircd socket path.
Definition lirc_config.h:34
PACKET_SIZE
#define PACKET_SIZE
IR transmission packet size.
Definition lirc_config.h:84
LIRCRC_ROOT_FILE
#define LIRCRC_ROOT_FILE
System-wide lircrc path.
Definition lirc_config.h:54
chk_write
#define chk_write(fd, buf, count)
Wrapper for write(2) which logs errors.
Definition lirc_log.h:215
lirc_cmd_ctx
The data needed to run a command on remote server.
Definition lirc_client.h:188
lirc_cmd_ctx::buffer
char buffer[PACKET_SIZE+1]
Reply IO buffer.
Definition lirc_client.h:190
lirc_cmd_ctx::reply_to_stdout
int reply_to_stdout
If true, write reply on stdout.
Definition lirc_client.h:193
lirc_cmd_ctx::next
char * next
Next newline-separated word in buffer.
Definition lirc_client.h:194
lirc_cmd_ctx::head
int head
First free buffer index.
Definition lirc_client.h:192
lirc_cmd_ctx::packet
char packet[PACKET_SIZE+1]
The packet to send.
Definition lirc_client.h:189
lirc_cmd_ctx::reply
char reply[PACKET_SIZE+1]
Command reply payload.
Definition lirc_client.h:191
lirc_code
Definition lirc_client.h:150
lirc_config_entry
Definition lirc_client.h:165
lirc_config
Definition lirc_client.h:156
lirc_config::lircrc_class
char * lircrc_class
The lircrc instance used, if any.
Definition lirc_client.h:157
lirc_list
Definition lirc_client.h:145