This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/doors.c
2017-04-23 12:31:03 +10:00

431 lines
9.0 KiB
C

#include <stdio.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <iconv.h>
#if defined(linux)
# include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
#else
# include <libutil.h>
#endif
#include "bbs.h"
#include "lua/lua.h"
#include "lua/lualib.h"
#include "lua/lauxlib.h"
extern struct bbs_config conf;
extern int mynode;
extern int gSocket;
extern int sshBBS;
extern int bbs_stderr;
int running_door_pid = 0;
int running_door = 0;
extern int timeoutpaused;
void doorchld_handler(int s)
{
// waitpid() might overwrite errno, so we save and restore it:
while(waitpid(-1, NULL, WNOHANG) > 0);
running_door = 0;
}
int write_door32sys(struct user_record *user) {
struct stat s;
char buffer[256];
FILE *fptr;
char *ptr;
int i;
sprintf(buffer, "%s/node%d", conf.bbs_path, mynode);
if (stat(buffer, &s) != 0) {
mkdir(buffer, 0755);
}
sprintf(buffer, "%s/node%d/door32.sys", conf.bbs_path, mynode);
fptr = fopen(buffer, "w");
if (!fptr) {
dolog("Unable to open %s for writing!", buffer);
return 1;
}
fprintf(fptr, "2\r\n"); // telnet type
fprintf(fptr, "%d\r\n", gSocket); // socket
fprintf(fptr, "38400\r\n"); // baudrate
fprintf(fptr, "Magicka %d.%d\r\n", VERSION_MAJOR, VERSION_MINOR);
fprintf(fptr, "%d\r\n", user->id);
fprintf(fptr, "%s %s\r\n", user->firstname, user->lastname);
fprintf(fptr, "%s\r\n", user->loginname);
fprintf(fptr, "%d\r\n", user->sec_level);
fprintf(fptr, "%d\r\n", user->timeleft);
fprintf(fptr, "1\r\n"); // ansi emulation = 1
fprintf(fptr, "%d\r\n", mynode);
fclose(fptr);
// create dorinfo1.def
sprintf(buffer, "%s/node%d", conf.bbs_path, mynode);
if (stat(buffer, &s) != 0) {
mkdir(buffer, 0755);
}
sprintf(buffer, "%s/node%d/dorinfo1.def", conf.bbs_path, mynode);
fptr = fopen(buffer, "w");
if (!fptr) {
dolog("Unable to open %s for writing!", buffer);
return 1;
}
strcpy(buffer, conf.sysop_name);
ptr = NULL;
for (i=0;i<strlen(buffer);i++) {
if (buffer[i] == ' ') {
ptr = &buffer[i+1];
buffer[i] = '\0';
break;
}
}
fprintf(fptr, "%s\r\n", conf.bbs_name); // telnet type
fprintf(fptr, "%s\r\n", buffer);
if (ptr != NULL) {
fprintf(fptr, "%s\r\n", ptr);
} else {
fprintf(fptr, "\r\n");
}
fprintf(fptr, "COM1\r\n"); // com port
fprintf(fptr, "38400 BAUD,N,8,1\r\n");
fprintf(fptr, "0\r\n");
fprintf(fptr, "%s\r\n", user->firstname);
fprintf(fptr, "%s\r\n", user->lastname);
fprintf(fptr, "%s\r\n", user->location);
fprintf(fptr, "1\r\n");
fprintf(fptr, "%d\r\n", user->sec_level);
fprintf(fptr, "%d\r\n", user->timeleft);
fprintf(fptr, "-1\r\n");
fclose(fptr);
return 0;
}
void rundoor(struct user_record *user, char *cmd, int stdio, char *codepage) {
char *arguments[4];
int door_out;
char buffer[10];
if (sshBBS) {
door_out = STDOUT_FILENO;
} else {
door_out = gSocket;
}
arguments[0] = strdup(cmd);
sprintf(buffer, "%d", mynode);
arguments[1] = strdup(buffer);
sprintf(buffer, "%d", door_out);
arguments[2] = strdup(buffer);
arguments[3] = NULL;
runexternal(user, cmd, stdio, arguments, NULL, 0, codepage);
free(arguments[0]);
free(arguments[1]);
free(arguments[2]);
}
void runexternal(struct user_record *user, char *cmd, int stdio, char *argv[], char *cwd, int raw, char *codepage) {
char buffer[1024];
int pid;
int ret;
unsigned char c;
int len;
int master;
int slave;
fd_set fdset;
int t;
struct winsize ws;
struct sigaction sa;
int door_in;
int door_out;
int i;
int gotiac;
int flush;
iconv_t ic;
struct timeval thetimeout;
struct termios oldit;
struct termios oldot;
struct termios oldit2;
char inbuf[256];
char outbuf[512];
int h;
int g;
char *ptr1;
char *ptr2;
size_t ouc;
size_t inc;
timeoutpaused = 1;
if (write_door32sys(user) != 0) {
return;
}
if (stdio) {
if (sshBBS) {
door_in = STDIN_FILENO;
door_out = STDOUT_FILENO;
} else {
door_in = gSocket;
door_out = gSocket;
}
ws.ws_row = 24;
ws.ws_col = 80;
running_door = 1;
if (!sshBBS) {
if (openpty(&master, &slave, NULL, NULL, &ws) == 0) {
sa.sa_handler = doorchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
if (raw) {
ttySetRaw(master, &oldit2);
ttySetRaw(slave, &oldit2);
}
pid = fork();
if (pid < 0) {
return;
} else if (pid == 0) {
if (cwd != NULL) {
chdir(cwd);
}
close(master);
dup2(slave, 0);
dup2(slave, 1);
close(slave);
setsid();
ioctl(0, TIOCSCTTY, 1);
execvp(cmd, argv);
} else {
running_door_pid = pid;
gotiac = 0;
flush = 0;
while(running_door || !flush) {
FD_ZERO(&fdset);
FD_SET(master, &fdset);
FD_SET(door_in, &fdset);
if (master > door_in) {
t = master + 1;
} else {
t = door_in + 1;
}
thetimeout.tv_sec = 5;
thetimeout.tv_usec = 0;
ret = select(t, &fdset, NULL, NULL, &thetimeout);
if (ret > 0) {
if (FD_ISSET(door_in, &fdset)) {
len = read(door_in, inbuf, 256);
if (len == 0) {
close(master);
disconnect("Socket Closed");
return;
}
g = 0;
for (h=0;h<len;h++) {
c = inbuf[h];
if (!raw) {
if (c == '\n' || c == '\0') {
continue;
}
}
if (!running_door) {
continue;
}
if (c == 255) {
if (gotiac == 1) {
outbuf[g++] = c;
gotiac = 0;
} else {
gotiac = 1;
}
} else {
if (gotiac == 1) {
if (c == 254 || c == 253 || c == 252 || c == 251) {
gotiac = 2;
} else if (c == 250) {
gotiac = 3;
} else {
gotiac = 0;
}
} else if (gotiac == 2) {
gotiac = 0;
} else if (gotiac == 3) {
if (c == 240) {
gotiac = 0;
}
} else {
outbuf[g++] = c;
}
}
}
if (codepage == NULL || (strcmp(codepage, "CP437") == 0 && gUser->codepage == 0) || (strcmp(codepage, "UTF-8") == 0 && gUser->codepage == 1)) {
write(master, outbuf, g);
} else {
if (gUser->codepage == 0) {
ic = iconv_open("CP437", codepage);
} else {
ic = iconv_open("UTF-8", codepage);
}
ptr1 = outbuf;
ptr2 = (char *)malloc((g + 1) * 2);
memset(ptr2, 0, (g + 1) * 2);
inc = g;
ouc = g * 2;
iconv(ic, &ptr1, &inc, &ptr2, &ouc);
ptr2 = ptr2 - (g * 2 - ouc);
write(master, ptr2, strlen(ptr2));
free(ptr2);
iconv_close(ic);
}
} else if (FD_ISSET(master, &fdset)) {
len = read(master, inbuf, 256);
if (len == 0) {
close(master);
break;
}
g = 0;
for (h=0;h<len;h++) {
c = inbuf[h];
if (c == 255) {
outbuf[g++] = c;
}
outbuf[g++] = c;
}
if (codepage == NULL || (strcmp(codepage, "CP437") == 0 && gUser->codepage == 0) || (strcmp(codepage, "UTF-8") == 0 && gUser->codepage == 1)) {
write(door_out, outbuf, g);
} else {
if (gUser->codepage == 0) {
ic = iconv_open(codepage, "CP437");
} else {
ic = iconv_open(codepage, "UTF-8");
}
ptr1 = outbuf;
ptr2 = (char *)malloc((g + 1) * 2);
memset(ptr2, 0, (g + 1) * 2);
inc = g;
ouc = g * 2;
iconv(ic, &ptr1, &inc, &ptr2, &ouc);
ptr2 = ptr2 - (g * 2 - ouc);
write(door_out, ptr2, strlen(ptr2));
free(ptr2);
iconv_close(ic);
}
}
} else {
if (!running_door) {
flush = 1;
}
}
}
}
}
} else {
if (raw) {
ttySetRaw(STDIN_FILENO, &oldit);
ttySetRaw(STDOUT_FILENO, &oldot);
}
sa.sa_handler = doorchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
pid = fork();
if (pid < 0) {
return;
} else if (pid == 0) {
if (cwd != NULL) {
chdir(cwd);
}
dup2(bbs_stderr, 2);
execvp(cmd, argv);
} else {
while(running_door) {
sleep(1);
}
}
if (raw) {
tcsetattr(STDIN_FILENO, TCSANOW, &oldit);
tcsetattr(STDOUT_FILENO, TCSANOW, &oldot);
}
}
} else {
if (!sshBBS) {
snprintf(buffer, 1024, "%s", cmd);
for (i=1;argv[i] != NULL; i++) {
snprintf(&buffer[strlen(buffer)], 1024 - strlen(buffer), " %s", argv[i]);
}
if (cwd != NULL) {
chdir(cwd);
}
system(buffer);
if (cwd != NULL) {
chdir(conf.bbs_path);
}
} else {
s_printf(get_string(51));
}
}
timeoutpaused = 0;
}