1 /* $Id: lirc_client.c,v 5.29 2009/07/08 19:38:22 lirc Exp $ */
2
3 /****************************************************************************
4 ** lirc_client.c ***********************************************************
5 ****************************************************************************
6 *
7 * lirc_client - common routines for lircd clients
8 *
9 * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
10 * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
11 *
12 * System wide LIRCRC support by Michal Svec <rebel@atrey.karlin.mff.cuni.cz>
13 */
14
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18
19 #include <errno.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31
32 #include "lirc_client.h"
33
34 /* internal defines */
35 #define MAX_INCLUDES 10
36 #define LIRC_READ 255
37 #define LIRC_PACKET_SIZE 255
38 /* three seconds */
39 #define LIRC_TIMEOUT 3
40
41 /* internal data structures */
42 struct filestack_t {
43 FILE *file;
44 char *name;
45 int line;
46 struct filestack_t *parent;
47 };
48
49 enum packet_state {
50 P_BEGIN,
51 P_MESSAGE,
52 P_STATUS,
53 P_DATA,
54 P_N,
55 P_DATA_N,
56 P_END
57 };
58
59 /* internal functions */
60 static void lirc_printf(char *format_str, ...);
61 static void lirc_perror(const char *s);
62 static int lirc_readline(char **line, FILE * f);
63 static char *lirc_trim(char *s);
64 static char lirc_parse_escape(char **s, const char *name, int line);
65 static void lirc_parse_string(char *s, const char *name, int line);
66 static void lirc_parse_include(char *s, const char *name, int line);
67 static int lirc_mode(char *token, char *token2, char **mode,
68 struct lirc_config_entry **new_config,
69 struct lirc_config_entry **first_config,
70 struct lirc_config_entry **last_config, int (check) (char *s), const char *name, int line);
71 /*
72 lircrc_config relies on this function, hence don't make it static
73 but it's not part of the official interface, so there's no guarantee
74 that it will stay available in the future
75 */
76 unsigned int lirc_flags(char *string);
77 static char *lirc_getfilename(const char *file, const char *current_file);
78 static FILE *lirc_open(const char *file, const char *current_file, char **full_name);
79 static struct filestack_t *stack_push(struct filestack_t *parent);
80 static struct filestack_t *stack_pop(struct filestack_t *entry);
81 static void stack_free(struct filestack_t *entry);
82 static int lirc_readconfig_only_internal(char *file,
83 struct lirc_config **config,
84 int (check) (char *s), char **full_name, char **sha_bang);
85 static char *lirc_startupmode(struct lirc_config_entry *first);
86 static void lirc_freeconfigentries(struct lirc_config_entry *first);
87 static void lirc_clearmode(struct lirc_config *config);
88 static char *lirc_execute(struct lirc_config *config, struct lirc_config_entry *scan);
89 static int lirc_iscode(struct lirc_config_entry *scan, char *remote, char *button, int rep);
90 static int lirc_code2char_internal(struct lirc_config *config, char *code, char **string, char **prog);
91 static const char *lirc_read_string(int fd);
92 static int lirc_identify(int sockfd);
93
94 static int lirc_send_command(int sockfd, const char *command, char *buf, size_t * buf_len, int *ret_status);
95
96 static int lirc_lircd;
97 static int lirc_verbose = 0;
98 static char *lirc_prog = NULL;
99 static char *lirc_buffer = NULL;
100
lirc_printf(char * format_str,...)101 static void lirc_printf(char *format_str, ...)
102 {
103 va_list ap;
104
105 if (!lirc_verbose)
106 return;
107
108 va_start(ap, format_str);
109 vfprintf(stderr, format_str, ap);
110 va_end(ap);
111 }
112
lirc_perror(const char * s)113 static void lirc_perror(const char *s)
114 {
115 if (!lirc_verbose)
116 return;
117
118 perror(s);
119 }
120
lirc_init(char * prog,int verbose)121 int lirc_init(char *prog, int verbose)
122 {
123 struct sockaddr_un addr;
124
125 /* connect to lircd */
126
127 if (prog == NULL || lirc_prog != NULL)
128 return (-1);
129 lirc_prog = strdup(prog);
130 lirc_verbose = verbose;
131 if (lirc_prog == NULL) {
132 lirc_printf("%s: out of memory\n", prog);
133 return (-1);
134 }
135
136 addr.sun_family = AF_UNIX;
137 strcpy(addr.sun_path, LIRCD);
138 lirc_lircd = socket(AF_UNIX, SOCK_STREAM, 0);
139 if (lirc_lircd == -1) {
140 lirc_printf("%s: could not open socket\n", lirc_prog);
141 lirc_perror(lirc_prog);
142 free(lirc_prog);
143 lirc_prog = NULL;
144 return (-1);
145 }
146 if (connect(lirc_lircd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
147 close(lirc_lircd);
148 lirc_printf("%s: could not connect to socket\n", lirc_prog);
149 lirc_perror(lirc_prog);
150 free(lirc_prog);
151 lirc_prog = NULL;
152 return (-1);
153 }
154 return (lirc_lircd);
155 }
156
lirc_deinit(void)157 int lirc_deinit(void)
158 {
159 if (lirc_prog != NULL) {
160 free(lirc_prog);
161 lirc_prog = NULL;
162 }
163 if (lirc_buffer != NULL) {
164 free(lirc_buffer);
165 lirc_buffer = NULL;
166 }
167 return (close(lirc_lircd));
168 }
169
lirc_readline(char ** line,FILE * f)170 static int lirc_readline(char **line, FILE * f)
171 {
172 char *newline, *ret, *enlargeline;
173 int len;
174
175 newline = (char *)malloc(LIRC_READ + 1);
176 if (newline == NULL) {
177 lirc_printf("%s: out of memory\n", lirc_prog);
178 return (-1);
179 }
180 len = 0;
181 while (1) {
182 ret = fgets(newline + len, LIRC_READ + 1, f);
183 if (ret == NULL) {
184 if (feof(f) && len > 0) {
185 *line = newline;
186 } else {
187 free(newline);
188 *line = NULL;
189 }
190 return (0);
191 }
192 len = strlen(newline);
193 if (newline[len - 1] == '\n') {
194 newline[len - 1] = 0;
195 *line = newline;
196 return (0);
197 }
198
199 enlargeline = (char *)realloc(newline, len + 1 + LIRC_READ);
200 if (enlargeline == NULL) {
201 free(newline);
202 lirc_printf("%s: out of memory\n", lirc_prog);
203 return (-1);
204 }
205 newline = enlargeline;
206 }
207 }
208
lirc_trim(char * s)209 static char *lirc_trim(char *s)
210 {
211 int len;
212
213 while (s[0] == ' ' || s[0] == '\t')
214 s++;
215 len = strlen(s);
216 while (len > 0) {
217 len--;
218 if (s[len] == ' ' || s[len] == '\t')
219 s[len] = 0;
220 else
221 break;
222 }
223 return (s);
224 }
225
226 /* parse standard C escape sequences + \@,\A-\Z is ^@,^A-^Z */
227
lirc_parse_escape(char ** s,const char * name,int line)228 static char lirc_parse_escape(char **s, const char *name, int line)
229 {
230
231 char c;
232 unsigned int i, overflow, count;
233 int digits_found, digit;
234
235 c = **s;
236 (*s)++;
237 switch (c) {
238 case 'a':
239 return ('\a');
240 case 'b':
241 return ('\b');
242 case 'e':
243 #if 0
244 case 'E': /* this should become ^E */
245 #endif
246 return (033);
247 case 'f':
248 return ('\f');
249 case 'n':
250 return ('\n');
251 case 'r':
252 return ('\r');
253 case 't':
254 return ('\t');
255 case 'v':
256 return ('\v');
257 case '\n':
258 return (0);
259 case 0:
260 (*s)--;
261 return 0;
262 case '0':
263 case '1':
264 case '2':
265 case '3':
266 case '4':
267 case '5':
268 case '6':
269 case '7':
270 i = c - '0';
271 count = 0;
272
273 while (++count < 3) {
274 c = *(*s)++;
275 if (c >= '0' && c <= '7') {
276 i = (i << 3) + c - '0';
277 } else {
278 (*s)--;
279 break;
280 }
281 }
282 if (i > (1 << CHAR_BIT) - 1) {
283 i &= (1 << CHAR_BIT) - 1;
284 lirc_printf("%s: octal escape sequence out of range in %s:%d\n", lirc_prog, name, line);
285 }
286 return ((char)i);
287 case 'x':
288 {
289 i = 0;
290 overflow = 0;
291 digits_found = 0;
292 for (;;) {
293 c = *(*s)++;
294 if (c >= '0' && c <= '9')
295 digit = c - '0';
296 else if (c >= 'a' && c <= 'f')
297 digit = c - 'a' + 10;
298 else if (c >= 'A' && c <= 'F')
299 digit = c - 'A' + 10;
300 else {
301 (*s)--;
302 break;
303 }
304 overflow |= i ^ (i << 4 >> 4);
305 i = (i << 4) + digit;
306 digits_found = 1;
307 }
308 if (!digits_found) {
309 lirc_printf("%s: \\x used with no "
310 "following hex digits in %s:%d\n", lirc_prog, name, line);
311 }
312 if (overflow || i > (1 << CHAR_BIT) - 1) {
313 i &= (1 << CHAR_BIT) - 1;
314 lirc_printf("%s: hex escape sequence out "
315 "of range in %s:%d\n", lirc_prog, name, line);
316 }
317 return ((char)i);
318 }
319 default:
320 if (c >= '@' && c <= 'Z')
321 return (c - '@');
322 return (c);
323 }
324 }
325
lirc_parse_string(char * s,const char * name,int line)326 static void lirc_parse_string(char *s, const char *name, int line)
327 {
328 char *t;
329
330 t = s;
331 while (*s != 0) {
332 if (*s == '\\') {
333 s++;
334 *t = lirc_parse_escape(&s, name, line);
335 t++;
336 } else {
337 *t = *s;
338 s++;
339 t++;
340 }
341 }
342 *t = 0;
343 }
344
lirc_parse_include(char * s,const char * name,int line)345 static void lirc_parse_include(char *s, const char *name, int line)
346 {
347 char last;
348 size_t len;
349
350 len = strlen(s);
351 if (len < 2) {
352 return;
353 }
354 last = s[len - 1];
355 if (*s != '"' && *s != '<') {
356 return;
357 }
358 if (*s == '"' && last != '"') {
359 return;
360 } else if (*s == '<' && last != '>') {
361 return;
362 }
363 s[len - 1] = 0;
364 memmove(s, s + 1, len - 2 + 1); /* terminating 0 is copied */
365 }
366
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)367 int lirc_mode(char *token, char *token2, char **mode,
368 struct lirc_config_entry **new_config,
369 struct lirc_config_entry **first_config,
370 struct lirc_config_entry **last_config, int (check) (char *s), const char *name, int line)
371 {
372 struct lirc_config_entry *new_entry;
373
374 new_entry = *new_config;
375 if (strcasecmp(token, "begin") == 0) {
376 if (token2 == NULL) {
377 if (new_entry == NULL) {
378 new_entry = (struct lirc_config_entry *)
379 malloc(sizeof(struct lirc_config_entry));
380 if (new_entry == NULL) {
381 lirc_printf("%s: out of memory\n", lirc_prog);
382 return (-1);
383 } else {
384 new_entry->prog = NULL;
385 new_entry->code = NULL;
386 new_entry->rep_delay = 0;
387 new_entry->rep = 0;
388 new_entry->config = NULL;
389 new_entry->change_mode = NULL;
390 new_entry->flags = none;
391 new_entry->mode = NULL;
392 new_entry->next_config = NULL;
393 new_entry->next_code = NULL;
394 new_entry->next = NULL;
395
396 *new_config = new_entry;
397 }
398 } else {
399 lirc_printf("%s: bad file format, %s:%d\n", lirc_prog, name, line);
400 return (-1);
401 }
402 } else {
403 if (new_entry == NULL && *mode == NULL) {
404 *mode = strdup(token2);
405 if (*mode == NULL) {
406 return (-1);
407 }
408 } else {
409 lirc_printf("%s: bad file format, %s:%d\n", lirc_prog, name, line);
410 return (-1);
411 }
412 }
413 } else if (strcasecmp(token, "end") == 0) {
414 if (token2 == NULL) {
415 if (new_entry != NULL) {
416 #if 0
417 if (new_entry->prog == NULL) {
418 lirc_printf("%s: prog missing in config before line %d\n", lirc_prog, line);
419 lirc_freeconfigentries(new_entry);
420 *new_config = NULL;
421 return (-1);
422 }
423 if (strcasecmp(new_entry->prog, lirc_prog) != 0) {
424 lirc_freeconfigentries(new_entry);
425 *new_config = NULL;
426 return (0);
427 }
428 #endif
429 new_entry->next_code = new_entry->code;
430 new_entry->next_config = new_entry->config;
431 if (*last_config == NULL) {
432 *first_config = new_entry;
433 *last_config = new_entry;
434 } else {
435 (*last_config)->next = new_entry;
436 *last_config = new_entry;
437 }
438 *new_config = NULL;
439
440 if (*mode != NULL) {
441 new_entry->mode = strdup(*mode);
442 if (new_entry->mode == NULL) {
443 lirc_printf("%s: out of memory\n", lirc_prog);
444 return (-1);
445 }
446 }
447
448 if (check != NULL &&
449 new_entry->prog != NULL && strcasecmp(new_entry->prog, lirc_prog) == 0) {
450 struct lirc_list *list;
451
452 list = new_entry->config;
453 while (list != NULL) {
454 if (check(list->string) == -1) {
455 return (-1);
456 }
457 list = list->next;
458 }
459 }
460
461 if (new_entry->rep_delay == 0 && new_entry->rep > 0) {
462 new_entry->rep_delay = new_entry->rep - 1;
463 }
464 } else {
465 lirc_printf("%s: %s:%d: 'end' without 'begin'\n", lirc_prog, name, line);
466 return (-1);
467 }
468 } else {
469 if (*mode != NULL) {
470 if (new_entry != NULL) {
471 lirc_printf("%s: %s:%d: missing 'end' token\n", lirc_prog, name, line);
472 return (-1);
473 }
474 if (strcasecmp(*mode, token2) == 0) {
475 free(*mode);
476 *mode = NULL;
477 } else {
478 lirc_printf("%s: \"%s\" doesn't "
479 "match mode \"%s\"\n", lirc_prog, token2, *mode);
480 return (-1);
481 }
482 } else {
483 lirc_printf("%s: %s:%d: 'end %s' without 'begin'\n", lirc_prog, name, line, token2);
484 return (-1);
485 }
486 }
487 } else {
488 lirc_printf("%s: unknown token \"%s\" in %s:%d ignored\n", lirc_prog, token, name, line);
489 }
490 return (0);
491 }
492
lirc_flags(char * string)493 unsigned int lirc_flags(char *string)
494 {
495 char *s;
496 unsigned int flags;
497
498 flags = none;
499 s = strtok(string, " \t|");
500 while (s) {
501 if (strcasecmp(s, "once") == 0) {
502 flags |= once;
503 } else if (strcasecmp(s, "quit") == 0) {
504 flags |= quit;
505 } else if (strcasecmp(s, "mode") == 0) {
506 flags |= mode;
507 } else if (strcasecmp(s, "startup_mode") == 0) {
508 flags |= startup_mode;
509 } else if (strcasecmp(s, "toggle_reset") == 0) {
510 flags |= toggle_reset;
511 } else {
512 lirc_printf("%s: unknown flag \"%s\"\n", lirc_prog, s);
513 }
514 s = strtok(NULL, " \t");
515 }
516 return (flags);
517 }
518
lirc_getfilename(const char * file,const char * current_file)519 static char *lirc_getfilename(const char *file, const char *current_file)
520 {
521 char *home, *filename;
522
523 if (file == NULL) {
524 home = getenv("HOME");
525 if (home == NULL) {
526 home = "/";
527 }
528 filename = (char *)malloc(strlen(home) + 1 + strlen(LIRCRC_USER_FILE) + 1);
529 if (filename == NULL) {
530 lirc_printf("%s: out of memory\n", lirc_prog);
531 return NULL;
532 }
533 strcpy(filename, home);
534 if (strlen(home) > 0 && filename[strlen(filename) - 1] != '/') {
535 strcat(filename, "/");
536 }
537 strcat(filename, LIRCRC_USER_FILE);
538 } else if (strncmp(file, "~/", 2) == 0) {
539 home = getenv("HOME");
540 if (home == NULL) {
541 home = "/";
542 }
543 filename = (char *)malloc(strlen(home) + strlen(file) + 1);
544 if (filename == NULL) {
545 lirc_printf("%s: out of memory\n", lirc_prog);
546 return NULL;
547 }
548 strcpy(filename, home);
549 strcat(filename, file + 1);
550 } else if (file[0] == '/' || current_file == NULL) {
551 /* absulute path or root */
552 filename = strdup(file);
553 if (filename == NULL) {
554 lirc_printf("%s: out of memory\n", lirc_prog);
555 return NULL;
556 }
557 } else {
558 /* get path from parent filename */
559 int pathlen = strlen(current_file);
560 while (pathlen > 0 && current_file[pathlen - 1] != '/')
561 pathlen--;
562 filename = (char *)malloc(pathlen + strlen(file) + 1);
563 if (filename == NULL) {
564 lirc_printf("%s: out of memory\n", lirc_prog);
565 return NULL;
566 }
567 memcpy(filename, current_file, pathlen);
568 filename[pathlen] = 0;
569 strcat(filename, file);
570 }
571 return filename;
572 }
573
lirc_open(const char * file,const char * current_file,char ** full_name)574 static FILE *lirc_open(const char *file, const char *current_file, char **full_name)
575 {
576 FILE *fin;
577 char *filename;
578
579 filename = lirc_getfilename(file, current_file);
580 if (filename == NULL) {
581 return NULL;
582 }
583
584 fin = fopen(filename, "r");
585 if (fin == NULL && (file != NULL || errno != ENOENT)) {
586 lirc_printf("%s: could not open config file %s\n", lirc_prog, filename);
587 lirc_perror(lirc_prog);
588 } else if (fin == NULL) {
589 const char *root_file = LIRCRC_ROOT_FILE;
590 fin = fopen(root_file, "r");
591 if (fin == NULL && errno == ENOENT) {
592 int save_errno = errno;
593 root_file = LIRCRC_OLD_ROOT_FILE;
594 fin = fopen(root_file, "r");
595 errno = save_errno;
596 }
597 if (fin == NULL && errno != ENOENT) {
598 lirc_printf("%s: could not open config file %s\n", lirc_prog, LIRCRC_ROOT_FILE);
599 lirc_perror(lirc_prog);
600 } else if (fin == NULL) {
601 lirc_printf("%s: could not open config files "
602 "%s and %s\n", lirc_prog, filename, LIRCRC_ROOT_FILE);
603 lirc_perror(lirc_prog);
604 } else {
605 free(filename);
606 filename = strdup(root_file);
607 if (filename == NULL) {
608 fclose(fin);
609 lirc_printf("%s: out of memory\n", lirc_prog);
610 return NULL;
611 }
612 }
613 }
614 if (full_name && fin != NULL) {
615 *full_name = filename;
616 } else {
617 free(filename);
618 }
619 return fin;
620 }
621
stack_push(struct filestack_t * parent)622 static struct filestack_t *stack_push(struct filestack_t *parent)
623 {
624 struct filestack_t *entry;
625 entry = malloc(sizeof(struct filestack_t));
626 if (entry == NULL) {
627 lirc_printf("%s: out of memory\n", lirc_prog);
628 return NULL;
629 }
630 entry->file = NULL;
631 entry->name = NULL;
632 entry->line = 0;
633 entry->parent = parent;
634 return entry;
635 }
636
stack_pop(struct filestack_t * entry)637 static struct filestack_t *stack_pop(struct filestack_t *entry)
638 {
639 struct filestack_t *parent = NULL;
640 if (entry) {
641 parent = entry->parent;
642 if (entry->name)
643 free(entry->name);
644 free(entry);
645 }
646 return parent;
647 }
648
stack_free(struct filestack_t * entry)649 static void stack_free(struct filestack_t *entry)
650 {
651 while (entry) {
652 entry = stack_pop(entry);
653 }
654 }
655
lirc_readconfig(char * file,struct lirc_config ** config,int (check)(char * s))656 int lirc_readconfig(char *file, struct lirc_config **config, int (check) (char *s))
657 {
658 struct sockaddr_un addr;
659 int sockfd = -1;
660 char *sha_bang, *sha_bang2, *filename;
661 char *command;
662 int ret;
663
664 filename = NULL;
665 sha_bang = NULL;
666 if (lirc_readconfig_only_internal(file, config, check, &filename, &sha_bang) == -1) {
667 return -1;
668 }
669
670 if (sha_bang == NULL) {
671 goto lirc_readconfig_compat;
672 }
673
674 /* connect to lircrcd */
675
676 addr.sun_family = AF_UNIX;
677 if (lirc_getsocketname(filename, addr.sun_path, sizeof(addr.sun_path)) > sizeof(addr.sun_path)) {
678 lirc_printf("%s: WARNING: file name too long\n", lirc_prog);
679 goto lirc_readconfig_compat;
680 }
681 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
682 if (sockfd == -1) {
683 lirc_printf("%s: WARNING: could not open socket\n", lirc_prog);
684 lirc_perror(lirc_prog);
685 goto lirc_readconfig_compat;
686 }
687 if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != -1) {
688 if (sha_bang != NULL)
689 free(sha_bang);
690 (*config)->sockfd = sockfd;
691 free(filename);
692
693 /* tell daemon lirc_prog */
694 if (lirc_identify(sockfd) == LIRC_RET_SUCCESS) {
695 /* we're connected */
696 return 0;
697 }
698 close(sockfd);
699 lirc_freeconfig(*config);
700 return -1;
701 }
702 close(sockfd);
703 sockfd = -1;
704
705 /* launch lircrcd */
706 sha_bang2 = sha_bang != NULL ? sha_bang : "lircrcd";
707
708 command = malloc(strlen(sha_bang2) + 1 + strlen(filename) + 1);
709 if (command == NULL) {
710 goto lirc_readconfig_compat;
711 }
712 strcpy(command, sha_bang2);
713 strcat(command, " ");
714 strcat(command, filename);
715
716 ret = system(command);
717
718 if (ret == -1 || WEXITSTATUS(ret) != EXIT_SUCCESS) {
719 goto lirc_readconfig_compat;
720 }
721
722 if (sha_bang != NULL)
723 free(sha_bang);
724 free(filename);
725
726 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
727 if (sockfd == -1) {
728 lirc_printf("%s: WARNING: could not open socket\n", lirc_prog);
729 lirc_perror(lirc_prog);
730 goto lirc_readconfig_compat;
731 }
732 if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != -1) {
733 if (lirc_identify(sockfd) == LIRC_RET_SUCCESS) {
734 (*config)->sockfd = sockfd;
735 return 0;
736 }
737 }
738 close(sockfd);
739 lirc_freeconfig(*config);
740 return -1;
741
742 lirc_readconfig_compat:
743 /* compat fallback */
744 if (sockfd != -1)
745 close(sockfd);
746 if (sha_bang != NULL)
747 free(sha_bang);
748 free(filename);
749 return 0;
750 }
751
lirc_readconfig_only(char * file,struct lirc_config ** config,int (check)(char * s))752 int lirc_readconfig_only(char *file, struct lirc_config **config, int (check) (char *s))
753 {
754 return lirc_readconfig_only_internal(file, config, check, NULL, NULL);
755 }
756
lirc_readconfig_only_internal(char * file,struct lirc_config ** config,int (check)(char * s),char ** full_name,char ** sha_bang)757 static int lirc_readconfig_only_internal(char *file,
758 struct lirc_config **config,
759 int (check) (char *s), char **full_name, char **sha_bang)
760 {
761 char *string, *eq, *token, *token2, *token3;
762 struct filestack_t *filestack, *stack_tmp;
763 int open_files;
764 struct lirc_config_entry *new_entry, *first, *last;
765 char *mode, *remote;
766 int ret = 0;
767 int firstline = 1;
768 char *save_full_name = NULL;
769
770 filestack = stack_push(NULL);
771 if (filestack == NULL) {
772 return -1;
773 }
774 filestack->file = lirc_open(file, NULL, &(filestack->name));
775 if (filestack->file == NULL) {
776 stack_free(filestack);
777 return -1;
778 }
779 filestack->line = 0;
780 open_files = 1;
781
782 first = new_entry = last = NULL;
783 mode = NULL;
784 remote = LIRC_ALL;
785 while (filestack) {
786 if ((ret = lirc_readline(&string, filestack->file)) == -1 || string == NULL) {
787 fclose(filestack->file);
788 if (open_files == 1 && full_name != NULL) {
789 save_full_name = filestack->name;
790 filestack->name = NULL;
791 }
792 filestack = stack_pop(filestack);
793 open_files--;
794 continue;
795 }
796 /* check for sha-bang */
797 if (firstline && sha_bang) {
798 firstline = 0;
799 if (strncmp(string, "#!", 2) == 0) {
800 *sha_bang = strdup(string + 2);
801 if (*sha_bang == NULL) {
802 lirc_printf("%s: out of memory\n", lirc_prog);
803 ret = -1;
804 free(string);
805 break;
806 }
807 }
808 }
809 filestack->line++;
810 eq = strchr(string, '=');
811 if (eq == NULL) {
812 token = strtok(string, " \t");
813 if (token == NULL) {
814 /* ignore empty line */
815 } else if (token[0] == '#') {
816 /* ignore comment */
817 } else if (strcasecmp(token, "include") == 0) {
818 if (open_files >= MAX_INCLUDES) {
819 lirc_printf("%s: too many files "
820 "included at %s:%d\n", lirc_prog, filestack->name, filestack->line);
821 ret = -1;
822 } else {
823 token2 = strtok(NULL, "");
824 token2 = lirc_trim(token2);
825 lirc_parse_include(token2, filestack->name, filestack->line);
826 stack_tmp = stack_push(filestack);
827 if (stack_tmp == NULL) {
828 ret = -1;
829 } else {
830 stack_tmp->file =
831 lirc_open(token2, filestack->name, &(stack_tmp->name));
832 stack_tmp->line = 0;
833 if (stack_tmp->file) {
834 open_files++;
835 filestack = stack_tmp;
836 } else {
837 stack_pop(stack_tmp);
838 ret = -1;
839 }
840 }
841 }
842 } else {
843 token2 = strtok(NULL, " \t");
844 if (token2 != NULL && (token3 = strtok(NULL, " \t")) != NULL) {
845 lirc_printf("%s: unexpected token in line %s:%d\n",
846 lirc_prog, filestack->name, filestack->line);
847 } else {
848 ret = lirc_mode(token, token2, &mode,
849 &new_entry, &first, &last,
850 check, filestack->name, filestack->line);
851 if (ret == 0) {
852 if (remote != LIRC_ALL)
853 free(remote);
854 remote = LIRC_ALL;
855 } else {
856 if (mode != NULL) {
857 free(mode);
858 mode = NULL;
859 }
860 if (new_entry != NULL) {
861 lirc_freeconfigentries(new_entry);
862 new_entry = NULL;
863 }
864 }
865 }
866 }
867 } else {
868 eq[0] = 0;
869 token = lirc_trim(string);
870 token2 = lirc_trim(eq + 1);
871 if (token[0] == '#') {
872 /* ignore comment */
873 } else if (new_entry == NULL) {
874 lirc_printf("%s: bad file format, %s:%d\n",
875 lirc_prog, filestack->name, filestack->line);
876 ret = -1;
877 } else {
878 token2 = strdup(token2);
879 if (token2 == NULL) {
880 lirc_printf("%s: out of memory\n", lirc_prog);
881 ret = -1;
882 } else if (strcasecmp(token, "prog") == 0) {
883 if (new_entry->prog != NULL)
884 free(new_entry->prog);
885 new_entry->prog = token2;
886 } else if (strcasecmp(token, "remote") == 0) {
887 if (remote != LIRC_ALL)
888 free(remote);
889
890 if (strcasecmp("*", token2) == 0) {
891 remote = LIRC_ALL;
892 free(token2);
893 } else {
894 remote = token2;
895 }
896 } else if (strcasecmp(token, "button") == 0) {
897 struct lirc_code *code;
898
899 code = (struct lirc_code *)
900 malloc(sizeof(struct lirc_code));
901 if (code == NULL) {
902 free(token2);
903 lirc_printf("%s: out of memory\n", lirc_prog);
904 ret = -1;
905 } else {
906 code->remote = remote;
907 if (strcasecmp("*", token2) == 0) {
908 code->button = LIRC_ALL;
909 free(token2);
910 } else {
911 code->button = token2;
912 }
913 code->next = NULL;
914
915 if (new_entry->code == NULL) {
916 new_entry->code = code;
917 } else {
918 new_entry->next_code->next = code;
919 }
920 new_entry->next_code = code;
921 if (remote != LIRC_ALL) {
922 remote = strdup(remote);
923 if (remote == NULL) {
924 lirc_printf("%s: out of memory\n", lirc_prog);
925 ret = -1;
926 }
927 }
928 }
929 } else if (strcasecmp(token, "delay") == 0) {
930 char *end;
931
932 errno = ERANGE + 1;
933 new_entry->rep_delay = strtoul(token2, &end, 0);
934 if ((new_entry->rep_delay == ULONG_MAX && errno == ERANGE)
935 || end[0] != 0 || strlen(token2) == 0) {
936 lirc_printf("%s: \"%s\" not"
937 " a valid number for delay\n", lirc_prog, token2);
938 }
939 free(token2);
940 } else if (strcasecmp(token, "repeat") == 0) {
941 char *end;
942
943 errno = ERANGE + 1;
944 new_entry->rep = strtoul(token2, &end, 0);
945 if ((new_entry->rep == ULONG_MAX && errno == ERANGE)
946 || end[0] != 0 || strlen(token2) == 0) {
947 lirc_printf("%s: \"%s\" not"
948 " a valid number for repeat\n", lirc_prog, token2);
949 }
950 free(token2);
951 } else if (strcasecmp(token, "config") == 0) {
952 struct lirc_list *new_list;
953
954 new_list = (struct lirc_list *)
955 malloc(sizeof(struct lirc_list));
956 if (new_list == NULL) {
957 free(token2);
958 lirc_printf("%s: out of memory\n", lirc_prog);
959 ret = -1;
960 } else {
961 lirc_parse_string(token2, filestack->name, filestack->line);
962 new_list->string = token2;
963 new_list->next = NULL;
964 if (new_entry->config == NULL) {
965 new_entry->config = new_list;
966 } else {
967 new_entry->next_config->next = new_list;
968 }
969 new_entry->next_config = new_list;
970 }
971 } else if (strcasecmp(token, "mode") == 0) {
972 if (new_entry->change_mode != NULL)
973 free(new_entry->change_mode);
974 new_entry->change_mode = token2;
975 } else if (strcasecmp(token, "flags") == 0) {
976 new_entry->flags = lirc_flags(token2);
977 free(token2);
978 } else {
979 free(token2);
980 lirc_printf("%s: unknown token \"%s\" in %s:%d ignored\n",
981 lirc_prog, token, filestack->name, filestack->line);
982 }
983 }
984 }
985 free(string);
986 if (ret == -1)
987 break;
988 }
989 if (remote != LIRC_ALL)
990 free(remote);
991 if (new_entry != NULL) {
992 if (ret == 0) {
993 ret = lirc_mode("end", NULL, &mode, &new_entry, &first, &last, check, "", 0);
994 lirc_printf("%s: warning: end token missing at end of file\n", lirc_prog);
995 } else {
996 lirc_freeconfigentries(new_entry);
997 new_entry = NULL;
998 }
999 }
1000 if (mode != NULL) {
1001 if (ret == 0) {
1002 lirc_printf("%s: warning: no end token found for mode \"%s\"\n", lirc_prog, mode);
1003 }
1004 free(mode);
1005 }
1006 if (ret == 0) {
1007 char *startupmode;
1008
1009 *config = (struct lirc_config *)
1010 malloc(sizeof(struct lirc_config));
1011 if (*config == NULL) {
1012 lirc_printf("%s: out of memory\n", lirc_prog);
1013 lirc_freeconfigentries(first);
1014 return (-1);
1015 }
1016 (*config)->first = first;
1017 (*config)->next = first;
1018 startupmode = lirc_startupmode((*config)->first);
1019 (*config)->current_mode = startupmode ? strdup(startupmode) : NULL;
1020 (*config)->sockfd = -1;
1021 if (full_name != NULL) {
1022 *full_name = save_full_name;
1023 save_full_name = NULL;
1024 }
1025 } else {
1026 *config = NULL;
1027 lirc_freeconfigentries(first);
1028 if (*sha_bang != NULL) {
1029 free(*sha_bang);
1030 *sha_bang = NULL;
1031 }
1032 }
1033 if (filestack) {
1034 stack_free(filestack);
1035 }
1036 if (save_full_name) {
1037 free(save_full_name);
1038 }
1039 return (ret);
1040 }
1041
lirc_startupmode(struct lirc_config_entry * first)1042 static char *lirc_startupmode(struct lirc_config_entry *first)
1043 {
1044 struct lirc_config_entry *scan;
1045 char *startupmode;
1046
1047 startupmode = NULL;
1048 scan = first;
1049 /* Set a startup mode based on flags=startup_mode */
1050 while (scan != NULL) {
1051 if (scan->flags & startup_mode) {
1052 if (scan->change_mode != NULL) {
1053 startupmode = scan->change_mode;
1054 /* Remove the startup mode or it confuses lirc mode system */
1055 scan->change_mode = NULL;
1056 break;
1057 } else {
1058 lirc_printf("%s: startup_mode flags requires 'mode ='\n", lirc_prog);
1059 }
1060 }
1061 scan = scan->next;
1062 }
1063
1064 /* Set a default mode if we find a mode = client app name */
1065 if (startupmode == NULL) {
1066 scan = first;
1067 while (scan != NULL) {
1068 if (scan->mode != NULL && strcasecmp(lirc_prog, scan->mode) == 0) {
1069 startupmode = lirc_prog;
1070 break;
1071 }
1072 scan = scan->next;
1073 }
1074 }
1075
1076 if (startupmode == NULL)
1077 return (NULL);
1078 scan = first;
1079 while (scan != NULL) {
1080 if (scan->change_mode != NULL && scan->flags & once && strcasecmp(startupmode, scan->change_mode) == 0) {
1081 scan->flags |= ecno;
1082 }
1083 scan = scan->next;
1084 }
1085 return (startupmode);
1086 }
1087
lirc_freeconfig(struct lirc_config * config)1088 void lirc_freeconfig(struct lirc_config *config)
1089 {
1090 if (config != NULL) {
1091 if (config->sockfd != -1) {
1092 (void)close(config->sockfd);
1093 config->sockfd = -1;
1094 }
1095 lirc_freeconfigentries(config->first);
1096 free(config->current_mode);
1097 free(config);
1098 }
1099 }
1100
lirc_freeconfigentries(struct lirc_config_entry * first)1101 static void lirc_freeconfigentries(struct lirc_config_entry *first)
1102 {
1103 struct lirc_config_entry *c, *config_temp;
1104 struct lirc_list *list, *list_temp;
1105 struct lirc_code *code, *code_temp;
1106
1107 c = first;
1108 while (c != NULL) {
1109 if (c->prog)
1110 free(c->prog);
1111 if (c->change_mode)
1112 free(c->change_mode);
1113 if (c->mode)
1114 free(c->mode);
1115
1116 code = c->code;
1117 while (code != NULL) {
1118 if (code->remote != NULL && code->remote != LIRC_ALL)
1119 free(code->remote);
1120 if (code->button != NULL && code->button != LIRC_ALL)
1121 free(code->button);
1122 code_temp = code->next;
1123 free(code);
1124 code = code_temp;
1125 }
1126
1127 list = c->config;
1128 while (list != NULL) {
1129 if (list->string)
1130 free(list->string);
1131 list_temp = list->next;
1132 free(list);
1133 list = list_temp;
1134 }
1135 config_temp = c->next;
1136 free(c);
1137 c = config_temp;
1138 }
1139 }
1140
lirc_clearmode(struct lirc_config * config)1141 static void lirc_clearmode(struct lirc_config *config)
1142 {
1143 struct lirc_config_entry *scan;
1144
1145 if (config->current_mode == NULL) {
1146 return;
1147 }
1148 scan = config->first;
1149 while (scan != NULL) {
1150 if (scan->change_mode != NULL) {
1151 if (strcasecmp(scan->change_mode, config->current_mode) == 0) {
1152 scan->flags &= ~ecno;
1153 }
1154 }
1155 scan = scan->next;
1156 }
1157 free(config->current_mode);
1158 config->current_mode = NULL;
1159 }
1160
lirc_execute(struct lirc_config * config,struct lirc_config_entry * scan)1161 static char *lirc_execute(struct lirc_config *config, struct lirc_config_entry *scan)
1162 {
1163 char *s;
1164 int do_once = 1;
1165
1166 if (scan->flags & mode) {
1167 lirc_clearmode(config);
1168 }
1169 if (scan->change_mode != NULL) {
1170 free(config->current_mode);
1171 config->current_mode = strdup(scan->change_mode);
1172 if (scan->flags & once) {
1173 if (scan->flags & ecno) {
1174 do_once = 0;
1175 } else {
1176 scan->flags |= ecno;
1177 }
1178 }
1179 }
1180 if (scan->next_config != NULL &&
1181 scan->prog != NULL && (lirc_prog == NULL || strcasecmp(scan->prog, lirc_prog) == 0) && do_once == 1) {
1182 s = scan->next_config->string;
1183 scan->next_config = scan->next_config->next;
1184 if (scan->next_config == NULL)
1185 scan->next_config = scan->config;
1186 return (s);
1187 }
1188 return (NULL);
1189 }
1190
lirc_iscode(struct lirc_config_entry * scan,char * remote,char * button,int rep)1191 static int lirc_iscode(struct lirc_config_entry *scan, char *remote, char *button, int rep)
1192 {
1193 struct lirc_code *codes;
1194
1195 /* no remote/button specified */
1196 if (scan->code == NULL) {
1197 return rep == 0 ||
1198 (scan->rep > 0 && rep > scan->rep_delay && ((rep - scan->rep_delay - 1) % scan->rep) == 0);
1199 }
1200
1201 /* remote/button match? */
1202 if (scan->next_code->remote == LIRC_ALL || strcasecmp(scan->next_code->remote, remote) == 0) {
1203 if (scan->next_code->button == LIRC_ALL || strcasecmp(scan->next_code->button, button) == 0) {
1204 int iscode = 0;
1205 /* button sequence? */
1206 if (scan->code->next == NULL || rep == 0) {
1207 scan->next_code = scan->next_code->next;
1208 if (scan->code->next != NULL) {
1209 iscode = 1;
1210 }
1211 }
1212 /* sequence completed? */
1213 if (scan->next_code == NULL) {
1214 scan->next_code = scan->code;
1215 if (scan->code->next != NULL || rep == 0 ||
1216 (scan->rep > 0 && rep > scan->rep_delay &&
1217 ((rep - scan->rep_delay - 1) % scan->rep) == 0))
1218 iscode = 2;
1219 }
1220 return iscode;
1221 }
1222 }
1223
1224 if (rep != 0)
1225 return (0);
1226
1227 /* handle toggle_reset */
1228 if (scan->flags & toggle_reset) {
1229 scan->next_config = scan->config;
1230 }
1231
1232 codes = scan->code;
1233 if (codes == scan->next_code)
1234 return (0);
1235 codes = codes->next;
1236 /* rebase code sequence */
1237 while (codes != scan->next_code->next) {
1238 struct lirc_code *prev, *next;
1239 int flag = 1;
1240
1241 prev = scan->code;
1242 next = codes;
1243 while (next != scan->next_code) {
1244 if (prev->remote == LIRC_ALL || strcasecmp(prev->remote, next->remote) == 0) {
1245 if (prev->button == LIRC_ALL || strcasecmp(prev->button, next->button) == 0) {
1246 prev = prev->next;
1247 next = next->next;
1248 } else {
1249 flag = 0;
1250 break;
1251 }
1252 } else {
1253 flag = 0;
1254 break;
1255 }
1256 }
1257 if (flag == 1) {
1258 if (prev->remote == LIRC_ALL || strcasecmp(prev->remote, remote) == 0) {
1259 if (prev->button == LIRC_ALL || strcasecmp(prev->button, button) == 0) {
1260 if (rep == 0) {
1261 scan->next_code = prev->next;
1262 return (0);
1263 }
1264 }
1265 }
1266 }
1267 codes = codes->next;
1268 }
1269 scan->next_code = scan->code;
1270 return (0);
1271 }
1272
lirc_ir2char(struct lirc_config * config,char * code)1273 char *lirc_ir2char(struct lirc_config *config, char *code)
1274 {
1275 static int warning = 1;
1276 char *string;
1277
1278 if (warning) {
1279 fprintf(stderr, "%s: warning: lirc_ir2char() is obsolete\n", lirc_prog);
1280 warning = 0;
1281 }
1282 if (lirc_code2char(config, code, &string) == -1)
1283 return (NULL);
1284 return (string);
1285 }
1286
lirc_code2char(struct lirc_config * config,char * code,char ** string)1287 int lirc_code2char(struct lirc_config *config, char *code, char **string)
1288 {
1289 if (config->sockfd != -1) {
1290 char command[10 + strlen(code) + 1 + 1];
1291 static char buf[LIRC_PACKET_SIZE];
1292 size_t buf_len = LIRC_PACKET_SIZE;
1293 int success;
1294 int ret;
1295
1296 sprintf(command, "CODE %s", code);
1297
1298 ret = lirc_send_command(config->sockfd, command, buf, &buf_len, &success);
1299 if (success == LIRC_RET_SUCCESS) {
1300 if (ret > 0) {
1301 *string = buf;
1302 } else {
1303 *string = NULL;
1304 }
1305 return LIRC_RET_SUCCESS;
1306 }
1307 return LIRC_RET_ERROR;
1308 }
1309 return lirc_code2char_internal(config, code, string, NULL);
1310 }
1311
lirc_code2charprog(struct lirc_config * config,char * code,char ** string,char ** prog)1312 int lirc_code2charprog(struct lirc_config *config, char *code, char **string, char **prog)
1313 {
1314 char *backup;
1315 int ret;
1316
1317 backup = lirc_prog;
1318 lirc_prog = NULL;
1319
1320 ret = lirc_code2char_internal(config, code, string, prog);
1321
1322 lirc_prog = backup;
1323 return ret;
1324 }
1325
lirc_code2char_internal(struct lirc_config * config,char * code,char ** string,char ** prog)1326 static int lirc_code2char_internal(struct lirc_config *config, char *code, char **string, char **prog)
1327 {
1328 int rep;
1329 char *backup;
1330 char *remote, *button;
1331 char *s = NULL;
1332 struct lirc_config_entry *scan;
1333 int exec_level;
1334 int quit_happened;
1335
1336 *string = NULL;
1337 if (sscanf(code, "%*x %x %*s %*s\n", &rep) == 1) {
1338 backup = strdup(code);
1339 if (backup == NULL)
1340 return (-1);
1341
1342 strtok(backup, " ");
1343 strtok(NULL, " ");
1344 button = strtok(NULL, " ");
1345 remote = strtok(NULL, "\n");
1346
1347 if (button == NULL || remote == NULL) {
1348 free(backup);
1349 return (0);
1350 }
1351
1352 scan = config->next;
1353 quit_happened = 0;
1354 while (scan != NULL) {
1355 exec_level = lirc_iscode(scan, remote, button, rep);
1356 if (exec_level > 0 &&
1357 (scan->mode == NULL ||
1358 (scan->mode != NULL &&
1359 config->current_mode != NULL &&
1360 strcasecmp(scan->mode, config->current_mode) == 0)) && quit_happened == 0) {
1361 if (exec_level > 1) {
1362 s = lirc_execute(config, scan);
1363 if (s != NULL && prog != NULL) {
1364 *prog = scan->prog;
1365 }
1366 } else {
1367 s = NULL;
1368 }
1369 if (scan->flags & quit) {
1370 quit_happened = 1;
1371 config->next = NULL;
1372 scan = scan->next;
1373 continue;
1374 } else if (s != NULL) {
1375 config->next = scan->next;
1376 break;
1377 }
1378 }
1379 scan = scan->next;
1380 }
1381 free(backup);
1382 if (s != NULL) {
1383 *string = s;
1384 return (0);
1385 }
1386 }
1387 config->next = config->first;
1388 return (0);
1389 }
1390
1391 #define PACKET_SIZE 100
1392
lirc_nextir(void)1393 char *lirc_nextir(void)
1394 {
1395 static int warning = 1;
1396 char *code;
1397 int ret;
1398
1399 if (warning) {
1400 fprintf(stderr, "%s: warning: lirc_nextir() is obsolete\n", lirc_prog);
1401 warning = 0;
1402 }
1403 ret = lirc_nextcode(&code);
1404 if (ret == -1)
1405 return (NULL);
1406 return (code);
1407 }
1408
lirc_nextcode(char ** code)1409 int lirc_nextcode(char **code)
1410 {
1411 static int packet_size = PACKET_SIZE;
1412 static int end_len = 0;
1413 ssize_t len = 0;
1414 char *end, c;
1415
1416 *code = NULL;
1417 if (lirc_buffer == NULL) {
1418 lirc_buffer = (char *)malloc(packet_size + 1);
1419 if (lirc_buffer == NULL) {
1420 lirc_printf("%s: out of memory\n", lirc_prog);
1421 return (-1);
1422 }
1423 lirc_buffer[0] = 0;
1424 }
1425 while ((end = strchr(lirc_buffer, '\n')) == NULL) {
1426 if (end_len >= packet_size) {
1427 char *new_buffer;
1428
1429 packet_size += PACKET_SIZE;
1430 new_buffer = (char *)realloc(lirc_buffer, packet_size + 1);
1431 if (new_buffer == NULL) {
1432 return (-1);
1433 }
1434 lirc_buffer = new_buffer;
1435 }
1436 len = read(lirc_lircd, lirc_buffer + end_len, packet_size - end_len);
1437 if (len <= 0) {
1438 if (len == -1 && errno == EAGAIN)
1439 return (0);
1440 else
1441 return (-1);
1442 }
1443 end_len += len;
1444 lirc_buffer[end_len] = 0;
1445 /* return if next code not yet available completely */
1446 if ((end = strchr(lirc_buffer, '\n')) == NULL) {
1447 return (0);
1448 }
1449 }
1450 /* copy first line to buffer (code) and move remaining chars to
1451 lirc_buffers start */
1452 end++;
1453 end_len = strlen(end);
1454 c = end[0];
1455 end[0] = 0;
1456 *code = strdup(lirc_buffer);
1457 end[0] = c;
1458 memmove(lirc_buffer, end, end_len + 1);
1459 if (*code == NULL)
1460 return (-1);
1461 return (0);
1462 }
1463
lirc_getsocketname(const char * filename,char * buf,size_t size)1464 size_t lirc_getsocketname(const char *filename, char *buf, size_t size)
1465 {
1466 if (strlen(filename) + 2 <= size) {
1467 strcpy(buf, filename);
1468 strcat(buf, "d");
1469 }
1470 return strlen(filename) + 2;
1471 }
1472
lirc_getmode(struct lirc_config * config)1473 const char *lirc_getmode(struct lirc_config *config)
1474 {
1475 if (config->sockfd != -1) {
1476 static char buf[LIRC_PACKET_SIZE];
1477 size_t buf_len = LIRC_PACKET_SIZE;
1478 int success;
1479 int ret;
1480
1481 ret = lirc_send_command(config->sockfd, "GETMODE\n", buf, &buf_len, &success);
1482 if (success == LIRC_RET_SUCCESS) {
1483 if (ret > 0) {
1484 return buf;
1485 } else {
1486 return NULL;
1487 }
1488 }
1489 return NULL;
1490 }
1491 return config->current_mode;
1492 }
1493
lirc_setmode(struct lirc_config * config,const char * mode)1494 const char *lirc_setmode(struct lirc_config *config, const char *mode)
1495 {
1496 if (config->sockfd != -1) {
1497 static char buf[LIRC_PACKET_SIZE];
1498 size_t buf_len = LIRC_PACKET_SIZE;
1499 int success;
1500 int ret;
1501 char cmd[LIRC_PACKET_SIZE];
1502 if (snprintf(cmd, LIRC_PACKET_SIZE, "SETMODE%s%s\n", mode ? " " : "", mode ? mode : "")
1503 >= LIRC_PACKET_SIZE) {
1504 return NULL;
1505 }
1506
1507 ret = lirc_send_command(config->sockfd, cmd, buf, &buf_len, &success);
1508 if (success == LIRC_RET_SUCCESS) {
1509 if (ret > 0) {
1510 return buf;
1511 } else {
1512 return NULL;
1513 }
1514 }
1515 return NULL;
1516 }
1517
1518 free(config->current_mode);
1519 config->current_mode = mode ? strdup(mode) : NULL;
1520 return config->current_mode;
1521 }
1522
lirc_read_string(int fd)1523 static const char *lirc_read_string(int fd)
1524 {
1525 static char buffer[LIRC_PACKET_SIZE + 1] = "";
1526 char *end;
1527 static int head = 0, tail = 0;
1528 int ret;
1529 ssize_t n;
1530 fd_set fds;
1531 struct timeval tv;
1532
1533 if (head > 0) {
1534 memmove(buffer, buffer + head, tail - head + 1);
1535 tail -= head;
1536 head = 0;
1537 end = strchr(buffer, '\n');
1538 } else {
1539 end = NULL;
1540 }
1541 if (strlen(buffer) != tail) {
1542 lirc_printf("%s: protocol error\n", lirc_prog);
1543 goto lirc_read_string_error;
1544 }
1545
1546 while (end == NULL) {
1547 if (LIRC_PACKET_SIZE <= tail) {
1548 lirc_printf("%s: bad packet\n", lirc_prog);
1549 goto lirc_read_string_error;
1550 }
1551
1552 FD_ZERO(&fds);
1553 FD_SET(fd, &fds);
1554 tv.tv_sec = LIRC_TIMEOUT;
1555 tv.tv_usec = 0;
1556 do {
1557 ret = select(fd + 1, &fds, NULL, NULL, &tv);
1558 }
1559 while (ret == -1 && errno == EINTR);
1560 if (ret == -1) {
1561 lirc_printf("%s: select() failed\n", lirc_prog);
1562 lirc_perror(lirc_prog);
1563 goto lirc_read_string_error;
1564 } else if (ret == 0) {
1565 lirc_printf("%s: timeout\n", lirc_prog);
1566 goto lirc_read_string_error;
1567 }
1568
1569 n = read(fd, buffer + tail, LIRC_PACKET_SIZE - tail);
1570 if (n <= 0) {
1571 lirc_printf("%s: read() failed\n", lirc_prog);
1572 lirc_perror(lirc_prog);
1573 goto lirc_read_string_error;
1574 }
1575 buffer[tail + n] = 0;
1576 tail += n;
1577 end = strchr(buffer, '\n');
1578 }
1579
1580 end[0] = 0;
1581 head = strlen(buffer) + 1;
1582 return (buffer);
1583
1584 lirc_read_string_error:
1585 head = tail = 0;
1586 buffer[0] = 0;
1587 return (NULL);
1588 }
1589
lirc_send_command(int sockfd,const char * command,char * buf,size_t * buf_len,int * ret_status)1590 int lirc_send_command(int sockfd, const char *command, char *buf, size_t * buf_len, int *ret_status)
1591 {
1592 int done, todo;
1593 const char *string, *data;
1594 char *endptr;
1595 enum packet_state state;
1596 int status, n;
1597 __u32 data_n = 0;
1598 size_t written = 0, max = 0, len;
1599
1600 if (buf_len != NULL) {
1601 max = *buf_len;
1602 }
1603 todo = strlen(command);
1604 data = command;
1605 while (todo > 0) {
1606 done = write(sockfd, (void *)data, todo);
1607 if (done < 0) {
1608 lirc_printf("%s: could not send packet\n", lirc_prog);
1609 lirc_perror(lirc_prog);
1610 return (-1);
1611 }
1612 data += done;
1613 todo -= done;
1614 }
1615
1616 /* get response */
1617 status = LIRC_RET_SUCCESS;
1618 state = P_BEGIN;
1619 n = 0;
1620 while (1) {
1621 string = lirc_read_string(sockfd);
1622 if (string == NULL)
1623 return (-1);
1624 switch (state) {
1625 case P_BEGIN:
1626 if (strcasecmp(string, "BEGIN") != 0) {
1627 continue;
1628 }
1629 state = P_MESSAGE;
1630 break;
1631 case P_MESSAGE:
1632 if (strncasecmp(string, command, strlen(string)) != 0 || strlen(string) + 1 != strlen(command)) {
1633 state = P_BEGIN;
1634 continue;
1635 }
1636 state = P_STATUS;
1637 break;
1638 case P_STATUS:
1639 if (strcasecmp(string, "SUCCESS") == 0) {
1640 status = LIRC_RET_SUCCESS;
1641 } else if (strcasecmp(string, "END") == 0) {
1642 status = LIRC_RET_SUCCESS;
1643 goto good_packet;
1644 } else if (strcasecmp(string, "ERROR") == 0) {
1645 lirc_printf("%s: command failed: %s", lirc_prog, command);
1646 status = LIRC_RET_ERROR;
1647 } else {
1648 goto bad_packet;
1649 }
1650 state = P_DATA;
1651 break;
1652 case P_DATA:
1653 if (strcasecmp(string, "END") == 0) {
1654 goto good_packet;
1655 } else if (strcasecmp(string, "DATA") == 0) {
1656 state = P_N;
1657 break;
1658 }
1659 goto bad_packet;
1660 case P_N:
1661 errno = 0;
1662 data_n = (__u32) strtoul(string, &endptr, 0);
1663 if (!*string || *endptr) {
1664 goto bad_packet;
1665 }
1666 if (data_n == 0) {
1667 state = P_END;
1668 } else {
1669 state = P_DATA_N;
1670 }
1671 break;
1672 case P_DATA_N:
1673 len = strlen(string);
1674 if (buf != NULL && written + len + 1 < max) {
1675 memcpy(buf + written, string, len + 1);
1676 }
1677 written += len + 1;
1678 n++;
1679 if (n == data_n)
1680 state = P_END;
1681 break;
1682 case P_END:
1683 if (strcasecmp(string, "END") == 0) {
1684 goto good_packet;
1685 }
1686 goto bad_packet;
1687 break;
1688 }
1689 }
1690
1691 /* never reached */
1692
1693 bad_packet:
1694 lirc_printf("%s: bad return packet\n", lirc_prog);
1695 return (-1);
1696
1697 good_packet:
1698 if (ret_status != NULL) {
1699 *ret_status = status;
1700 }
1701 if (buf_len != NULL) {
1702 *buf_len = written;
1703 }
1704 return (int)data_n;
1705 }
1706
lirc_identify(int sockfd)1707 int lirc_identify(int sockfd)
1708 {
1709 char command[10 + strlen(lirc_prog) + 1 + 1];
1710 int success;
1711
1712 sprintf(command, "IDENT %s\n", lirc_prog);
1713
1714 (void)lirc_send_command(sockfd, command, NULL, NULL, &success);
1715 return success;
1716 }
1717