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