/* Simple Client WJ97 */ #include "inet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_DATA_LINE 256 char *error_msg[] = { "Connection established", "Generic error", "Invalid internet address", "This system has no TCP protocol!", "Failed to create socket", "Failed to set socket options", "Failed to bind socket", "Failed to connect to host", "Insufficient memory", "Can't set socket non-blocking", "Already connected to that site", "Unknown error", }; int telnet_state = TS_DATA, in_sub = 0; int esc_state = ESC_DATA, esc_idx = 0; short esc_codes[MAX_ESC_CODES]; void terminal_mode(int mode) { static struct termios ori_term; struct termios term; if (!isatty(fileno(stdin))) return; tcgetattr(fileno(stdin), &term); if (mode) { memcpy(&ori_term, &term, sizeof(struct termios)); term.c_lflag &= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG); term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; } else memcpy(&term, &ori_term, sizeof(struct termios)); tcsetattr(fileno(stdin), TCSANOW, &term); } int inet_connect(char *site, int port, unsigned long *ipnumber) { struct hostent *host; struct protoent *proto; struct sockaddr_in addr; int sock, optval; if ((host = gethostbyname(site)) == NULL || host->h_addr == NULL) return CONNECTERR_INVAL_ADDR; if (ipnumber != NULL) *ipnumber = htonl(*((long *)host->h_addr)); if ((proto = getprotobyname("tcp")) == NULL) return CONNECTERR_NO_TCP; if ((sock = socket(AF_INET, SOCK_STREAM, proto->p_proto)) <= 0) return CONNECTERR_CREATSOCK; optval = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) { shutdown(sock, 2); close(sock); return CONNECTERR_SOCKOPT; } addr.sin_family = AF_INET; memcpy(&(addr.sin_addr), host->h_addr, sizeof(struct in_addr)); addr.sin_port = htons(port); if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) { shutdown(sock, 2); close(sock); return CONNECTERR_CONNECT; } optval = 1; if (ioctl(sock, FIONBIO, &optval) == -1) { printf("Cannot set socket non-blocking\n"); shutdown(sock, 2); close(sock); return -1; } return sock; } char *inet_error(int i) { return ((i <= 0 && i >= CONNECTERR_MAX) ? error_msg[-i] : error_msg[-(CONNECTERR_UNKNOWN)]); } /* Returns 0 on data, -1 on processed telnet command */ int telnet_filter(unsigned char c, int sock) { unsigned char answer[3]; *answer = IAC; switch(telnet_state) { case TS_DATA: if (c == IAC) { telnet_state = TS_IAC; break; } return 0; case TS_IAC: switch(c) { case DONT: telnet_state = TS_DONT; break; case DO: telnet_state = TS_DO; break; case WILL: telnet_state = TS_WILL; break; case WONT: telnet_state = TS_WONT; break; case AYT: write(sock, "\r\n[Yes]\r\n", 9); telnet_state = TS_DATA; break; case SB: in_sub++; break; case SE: in_sub--; if (in_sub < 0) in_sub = 0; if (!in_sub) telnet_state = TS_DATA; break; case NOP: telnet_state = TS_DATA; break; } break; case TS_WILL: case TS_DO: answer[1] = 0; switch(c) { case TELOPT_SGA: /* telnet_flags |= SESSION_NOLINE; */ if (telnet_state == TS_WILL) answer[1] = DO; break; case TELOPT_ECHO: /* telnet_flags |= SESSION_NOECHO; */ if (telnet_state == TS_WILL) answer[1] = DO; break; #ifndef TELOPT_LINEMODE case 34: #else case TELOPT_LINEMODE: #endif /* flags &= ~SESSION_NOLINE; */ if (telnet_state == TS_WILL) answer[1] = DO; break; default: if (telnet_state == TS_DO) answer[1] = WONT; } if (answer[1]) { answer[2] = c; write(sock, answer, 3); } telnet_state = TS_DATA; break; case TS_WONT: case TS_DONT: answer[1] = 0; switch(c) { case TELOPT_SGA: /* flags &= ~SESSION_NOLINE; */ if (telnet_state == TS_WONT) answer[1] = DO; break; case TELOPT_ECHO: /* flags &= ~SESSION_NOECHO; */ if (telnet_state == TS_WONT) answer[1] = DO; break; #ifndef TELOPT_LINEMODE case 34: #else case TELOPT_LINEMODE: #endif /* flags |= SESSION_NOLINE; */ if (telnet_state == TS_WONT) answer[1] = DO; break; default: if (telnet_state == TS_WONT) answer[1] = DONT; } if (answer[1]) { answer[2] = c; write(sock, answer, 3); } telnet_state = TS_DATA; break; } return -1; } /* Escape filter, returns commands to caller */ int esc_filter(char c) { int cmd = ESC_CMD_OK; switch(esc_state) { case ESC_DATA: if (c == 27) { esc_state = ESC_BRACE; cmd = ESC_CMD_IGNORE; } else if (c == 7 || c == '\r') cmd = ESC_CMD_IGNORE; break; case ESC_BRACE: if (c == '[') { esc_state = ESC_CODE; esc_idx = 0; cmd = ESC_CMD_IGNORE; } break; case ESC_CODE: cmd = ESC_CMD_IGNORE; if (c == ';') { /* more codes follow */ if (esc_idx < MAX_ESC_CODES) esc_idx++; return cmd; } if (c >= '0' && c <= '9') { if (esc_idx < MAX_ESC_CODES) { esc_codes[esc_idx] *= 10; esc_codes[esc_idx] += (c - '0'); } } else { int i; if (esc_idx < MAX_ESC_CODES) esc_idx++; /* .. removed large block of code here.. (See Session.cpp for original) */ cmd = ESC_CMD_UNSUPPORTED; for(i = 0; i < MAX_ESC_CODES; i++) esc_codes[i] = 0; esc_idx = 0; esc_state = ESC_DATA; break; } break; } return cmd; } int mainloop(char *site, int port) { int err, sock, read_pipe = -1, logfile = -1, buf2_idx = 0, i; char buf[MAX_DATA_LINE] = "", buf2[MAX_DATA_LINE] = "", c; fd_set fds; struct timeval timeout; memset(esc_codes, 0, MAX_ESC_CODES*sizeof(short)); if ((logfile = open("logfile", O_WRONLY | O_CREAT | O_APPEND, (mode_t)0600)) <= 0) printf("Note: Failed to open logfile\n"); if ((read_pipe = open("upload", O_RDONLY | O_NONBLOCK)) <= 0) { printf("Error opening read pipe\n"); return -1; } if ((sock = inet_connect(site, port, NULL)) < 0) { printf("Error: %s\n", inet_error(sock)); return -1; } printf("Connected, escape character is ^]\n"); terminal_mode(1); for(;;) { FD_ZERO(&fds); FD_SET(fileno(stdin), &fds); FD_SET(sock, &fds); if (read_pipe > 0) FD_SET(read_pipe, &fds); timeout.tv_sec = 600; timeout.tv_usec = 0; if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { if (FD_ISSET(sock, &fds)) { err = read(sock, buf, MAX_DATA_LINE-3); if (err == -1 || !err) { printf("\nConnection closed.\n"); break; } if (err > 0) { buf[err] = 0; buf2_idx = 0; for(i = 0; i < err; i++) if (!telnet_filter(buf[i], sock)) buf2[buf2_idx++] = buf[i]; buf2[buf2_idx] = 0; if (buf2_idx) { write(fileno(stdout), buf2, buf2_idx); if (logfile > 0) { buf2_idx = 0; for(i = 0; buf2[i]; i++) if (esc_filter(buf2[i]) == ESC_CMD_OK) buf[buf2_idx++] = buf2[i]; buf[buf2_idx] = 0; if (buf2_idx) write(logfile, buf, buf2_idx); } } } } if (FD_ISSET(fileno(stdin), &fds)) { err = read(fileno(stdin), &c, 1); if (err < 0) break; if (err >= 1) { if (c == 29) break; if (c == '\n') c = '\r'; write(sock, &c, 1); } } if (read_pipe > 0 && FD_ISSET(read_pipe, &fds)) { for(;;) { err = read(read_pipe, buf, 255); if (err <= 0) { close(read_pipe); read_pipe = open("upload", O_RDONLY | O_NONBLOCK); if (read_pipe <= 0) printf("[NOTE]: Failed to re-open read pipe 'upload'\n"); break; } for(i = 0; i < err; i++) if (buf[i] == '\n') buf[i] = '\r'; write(sock, buf, err); } } } } shutdown(sock, 2); close(sock); if (logfile > 0) close(logfile); terminal_mode(0); printf("\x1b[0m\n"); return 0; } int main(int argc, char **argv) { char *p, *site = "bbs.hro.nl"; int port = 0; if ((p = strrchr(argv[0], '/')) == NULL) p = argv[0]; else p++; if (argc > 1) site = argv[1]; if (argc > 2) port = atoi(argv[2]); if (!port) port = 23; return mainloop(site, port); } /* EOB */