aboutsummaryrefslogtreecommitdiffstats
path: root/vexnc.c
blob: 039b72365e1e7689ca1524e5207b4950382a19f4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <rfb/rfb.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

int logdirenabled = 0;
int fdlog = -1;
char logfn[64] = "";

int mkderp(const char *name) {
  int ret = mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO);
  if (ret < 0 && errno == EEXIST) {
    return 0;
  }
  return ret;
}

int spewtxt(int fd, const char *fmt, ...) {
  va_list va;
  char buf[256] = {0xF0, 0x9F, 0xBF, 0xBF, '\n', 0};

  va_start(va, fmt);
  vsnprintf(buf + 5, sizeof(buf) - 5, fmt, va);
  va_end(va);

  size_t len = strlen(buf);
  buf[len++] = '\n';

  return write(fd, buf, len);
}

int spewchr(int fd, uint16_t chr) {
  char buf[4];
  int i = 0;
  if (chr < 0x80) {
    buf[i++] = chr;
  } else if (chr < 0x800) {
    buf[i++] = 0xC0 | chr >> 6;
    buf[i++] = 0x80 | chr & 0x3F;
  } else {
    buf[i++] = 0xE0 | chr >> 12;
    buf[i++] = 0x80 | (chr >> 6) & 0x3F;
    buf[i++] = 0x80 | chr & 0x3F;
  }
  return write(fd, buf, i);
}

int openlogfile() {
  char curfn[64];
  time_t now;
  time(&now);
  strftime(curfn, 64, "%Y-%m-%d_%H", localtime(&now));
  if (!strncmp(curfn, logfn, 64))
    return 0;

  int fd = open(curfn, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (fd < 0) {
    perror("open logfile");
    return 1;
  }

  if (fdlog != -1 && close(fdlog) < 0) {
    perror("close logfile");
  }

  fdlog = fd;
  return 0;
}

void userofflog(rfbClientRec *cl) {
  if (openlogfile()) return;
  if (spewtxt(fdlog, "disconnect %s", cl->host) < 0)
    perror("spewtxt");
}

enum rfbNewClientAction useronlog(rfbClientRec *cl) {
  cl->clientGoneHook = userofflog;
  if (openlogfile()) return RFB_CLIENT_ACCEPT;
  if (spewtxt(fdlog, "connect %s", cl->host) < 0)
    perror("spewtxt");
  return RFB_CLIENT_ACCEPT;
}

void keylog(rfbBool down, rfbKeySym keySym, rfbClientRec* cl) {
  if (!down) return; // only log key downs
  if (openlogfile()) return; // ensure log file opened

  if (spewchr(fdlog, (uint16_t) keySym) < 0)
    perror("spewchr");
}

int main(int argc, char const *argv[]) {
  if (argc < 3) {
    printf("usage: %s IMAGEFILE TITLE [LOGDIR]\n", argv[0]);
    return 0;
  }

  if (argc >= 4) {
    if (mkderp(argv[3]) < 0) {
      perror("mkdir logdir");
      return 1;
    }
    if (chdir(argv[3]) < 0) {
      perror("chdir logdir");
      return 1;
    }
    logdirenabled = 1;
  }

  int imx, imy, imc;
  unsigned char *im = stbi_load(argv[1], &imx, &imy, &imc, 4);
  if (im == NULL) {
    printf("bad image: %s\n", stbi_failure_reason());
    return 1;
  }

  rfbScreenInfoPtr rfbScreen = rfbGetScreen(NULL, NULL, imx, imy, 8, 3, 4);
  rfbScreen->desktopName = argv[2] ? argv[2] : "";
  rfbScreen->frameBuffer = (char*)im;
  rfbScreen->alwaysShared = TRUE;
  if (logdirenabled) {
    rfbScreen->newClientHook = useronlog;
    rfbScreen->kbdAddEvent = keylog;
  }

  rfbInitServer(rfbScreen);
  rfbRunEventLoop(rfbScreen, -1, FALSE);

  stbi_image_free(im);
  rfbScreenCleanup(rfbScreen);

  return 0;
}