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