#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <linux/lirc.h>

static struct lirc_scancode sc[64];

int main(void)
{
  unsigned mode = LIRC_MODE_SCANCODE;
  int fd, s;
  struct sockaddr_un name;

  memset(&name, 0, sizeof name);
  name.sun_family = AF_UNIX;
  strncpy(name.sun_path, "/dev/shm/lirc", sizeof name.sun_path - 1);

  s = socket(AF_UNIX, SOCK_STREAM, 0);

  if (s == -1) {
    perror("socket");
    return 1;
  }

  if (bind(s, (const struct sockaddr*) &name, sizeof name) == -1) {
    perror("bind");
    return 1;
  }

  fd = open("/dev/lirc0", O_RDONLY | O_NONBLOCK);

  if (fd == -1) {
    perror("open");
    return 1;
  }
  if (ioctl(fd, LIRC_SET_REC_MODE, &mode)) {
    perror("ioctl");
    return 1;
  }

  if (listen(s, 1) == -1) {
    perror("listen");
    return 2;
  }

  for (;;) {
    int sock = accept(s, NULL, NULL);
    if (sock == -1) {
      perror("accept");
      return 2;
    }
    for (;;) {
      ssize_t rd;
      struct pollfd polls[2] = {
        { .fd = fd, .events = POLLIN },
        { .fd = sock, .events = POLLERR },
      };
      if (poll(polls, 2, -1) < 0) {
        if (errno == EINTR)
          continue;
        perror("poll");
        return 2;
      }
      rd = read(fd, sc, sizeof sc);
      if (rd > 0) {
        ssize_t i, n = rd / sizeof *sc;
        char buf[14];
        for (i = 0; i < n; i++) {
          int l = sprintf(buf, "0 0 %08x\n", sc[i].keycode);
          if (-1 == write(sock, buf, 13)) {
            perror("write");
            goto end;
          }
        }
      } else if (errno == EAGAIN) {
        continue;
      } else {
        perror("read");
        return 2;
      }
    }
end:
    close(sock);
  }
}
