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