Command line options with getopt_long
This commit is contained in:
parent
022782ce09
commit
672b3abae0
338
src/nyancat.c
338
src/nyancat.c
@ -59,6 +59,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
#ifndef TIOCGWINSZ
|
#ifndef TIOCGWINSZ
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
@ -236,6 +237,17 @@ void send_command(int cmd, int opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usage(char * argv[]) {
|
||||||
|
printf(
|
||||||
|
"Terminal Nyancat\n"
|
||||||
|
"\n"
|
||||||
|
"usage: %s [-h] [-t] [-i] \n"
|
||||||
|
"\n"
|
||||||
|
" -i --intro \033[3mShow the introduction / about informaiton at startup.\033[0m\n"
|
||||||
|
" -t --telnet \033[3mTelnet mode.\033[0m\n",
|
||||||
|
" -h --help \033[3mShow this help message.\033[0m\n",
|
||||||
|
argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
|
|
||||||
@ -249,126 +261,160 @@ int main(int argc, char ** argv) {
|
|||||||
char sb[1024] = {0};
|
char sb[1024] = {0};
|
||||||
char sb_len = 0;
|
char sb_len = 0;
|
||||||
|
|
||||||
if (argc > 1) {
|
char show_intro = 0;
|
||||||
if (!strcmp(argv[1], "-t")) {
|
|
||||||
/* Yes, I know, lame way to get arguments, whatever, we only want one of them. */
|
|
||||||
telnet = 1;
|
|
||||||
|
|
||||||
/* Set the default options */
|
/* Long option names */
|
||||||
set_options();
|
static struct option long_opts[] = {
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"telnet", no_argument, 0, 't'},
|
||||||
|
{"intro", no_argument, 0, 'i'},
|
||||||
|
{0,0,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
/* Let the client know what we're using */
|
/* Process arguments */
|
||||||
for (option = 0; option < 256; option++) {
|
int index, c;
|
||||||
if (telnet_options[option]) {
|
while ((c = getopt_long(argc, argv, "hit", long_opts, &index)) != -1) {
|
||||||
send_command(telnet_options[option], option);
|
if (!c) {
|
||||||
fflush(stdout);
|
if (long_opts[index].flag == 0) {
|
||||||
}
|
c = long_opts[index].val;
|
||||||
}
|
}
|
||||||
for (option = 0; option < 256; option++) {
|
}
|
||||||
if (telnet_willack[option]) {
|
switch (c) {
|
||||||
send_command(telnet_willack[option], option);
|
case 'i': /* Show introduction */
|
||||||
fflush(stdout);
|
show_intro = 1;
|
||||||
}
|
break;
|
||||||
|
case 't': /* Expect telnet bits */
|
||||||
|
telnet = 1;
|
||||||
|
break;
|
||||||
|
case 'h': /* Show help and exit */
|
||||||
|
usage(argv);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (telnet) {
|
||||||
|
/* Telnet mode */
|
||||||
|
|
||||||
|
/* Intro is implied by telnet mode, so override whatever was asked for. */
|
||||||
|
show_intro = 1;
|
||||||
|
|
||||||
|
/* Set the default options */
|
||||||
|
set_options();
|
||||||
|
|
||||||
|
/* Let the client know what we're using */
|
||||||
|
for (option = 0; option < 256; option++) {
|
||||||
|
if (telnet_options[option]) {
|
||||||
|
send_command(telnet_options[option], option);
|
||||||
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
for (option = 0; option < 256; option++) {
|
||||||
|
if (telnet_willack[option]) {
|
||||||
|
send_command(telnet_willack[option], option);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the alarm handler to execute the longjmp */
|
/* Set the alarm handler to execute the longjmp */
|
||||||
signal(SIGALRM, SIGALRM_handler);
|
signal(SIGALRM, SIGALRM_handler);
|
||||||
|
|
||||||
/* Negotiate options */
|
/* Negotiate options */
|
||||||
if (!setjmp(environment)) {
|
if (!setjmp(environment)) {
|
||||||
/* We will stop handling options after one second */
|
/* We will stop handling options after one second */
|
||||||
alarm(1);
|
alarm(1);
|
||||||
|
|
||||||
/* Let's do this */
|
/* Let's do this */
|
||||||
while (!feof(stdin) && done < 2) {
|
while (!feof(stdin) && done < 2) {
|
||||||
/* Get either IAC (start command) or a regular character (break, unless in SB mode) */
|
/* Get either IAC (start command) or a regular character (break, unless in SB mode) */
|
||||||
unsigned char i = getchar();
|
unsigned char i = getchar();
|
||||||
unsigned char opt = 0;
|
unsigned char opt = 0;
|
||||||
if (i == IAC) {
|
if (i == IAC) {
|
||||||
/* If IAC, get the command */
|
/* If IAC, get the command */
|
||||||
i = getchar();
|
i = getchar();
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case SE:
|
case SE:
|
||||||
/* End of extended option mode */
|
/* End of extended option mode */
|
||||||
sb_mode = 0;
|
sb_mode = 0;
|
||||||
if (sb[0] == TTYPE) {
|
if (sb[0] == TTYPE) {
|
||||||
/* This was a response to the TTYPE command, meaning
|
/* This was a response to the TTYPE command, meaning
|
||||||
* that this should be a terminal type */
|
* that this should be a terminal type */
|
||||||
alarm(0);
|
alarm(0);
|
||||||
strcpy(term, &sb[2]);
|
strcpy(term, &sb[2]);
|
||||||
done++;
|
done++;
|
||||||
}
|
}
|
||||||
else if (sb[0] == NAWS) {
|
else if (sb[0] == NAWS) {
|
||||||
/* This was a response to the NAWS command, meaning
|
/* This was a response to the NAWS command, meaning
|
||||||
* that this should be a window size */
|
* that this should be a window size */
|
||||||
alarm(0);
|
alarm(0);
|
||||||
terminal_width = sb[2];
|
terminal_width = sb[2];
|
||||||
done++;
|
done++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NOP:
|
case NOP:
|
||||||
/* No Op */
|
/* No Op */
|
||||||
send_command(NOP, 0);
|
send_command(NOP, 0);
|
||||||
|
fflush(stdout);
|
||||||
|
break;
|
||||||
|
case WILL:
|
||||||
|
case WONT:
|
||||||
|
/* Will / Won't Negotiation */
|
||||||
|
opt = getchar();
|
||||||
|
if (!telnet_willack[opt]) {
|
||||||
|
/* We default to WONT */
|
||||||
|
telnet_willack[opt] = WONT;
|
||||||
|
}
|
||||||
|
send_command(telnet_willack[opt], opt);
|
||||||
|
fflush(stdout);
|
||||||
|
if ((i == WILL) && (opt == TTYPE)) {
|
||||||
|
/* WILL TTYPE? Great, let's do that now! */
|
||||||
|
printf("%c%c%c%c%c%c", IAC, SB, TTYPE, SEND, IAC, SE);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
break;
|
}
|
||||||
case WILL:
|
break;
|
||||||
case WONT:
|
case DO:
|
||||||
/* Will / Won't Negotiation */
|
case DONT:
|
||||||
opt = getchar();
|
/* Do / Don't Negotation */
|
||||||
if (!telnet_willack[opt]) {
|
opt = getchar();
|
||||||
/* We default to WONT */
|
if (!telnet_options[opt]) {
|
||||||
telnet_willack[opt] = WONT;
|
/* We default to DONT */
|
||||||
}
|
telnet_options[opt] = DONT;
|
||||||
send_command(telnet_willack[opt], opt);
|
}
|
||||||
fflush(stdout);
|
send_command(telnet_options[opt], opt);
|
||||||
if ((i == WILL) && (opt == TTYPE)) {
|
if (opt == ECHO) {
|
||||||
/* WILL TTYPE? Great, let's do that now! */
|
/* We don't really need this, as we don't accept input, but,
|
||||||
printf("%c%c%c%c%c%c", IAC, SB, TTYPE, SEND, IAC, SE);
|
* in case we do in the future, set our echo mode */
|
||||||
fflush(stdout);
|
do_echo = (i == DO);
|
||||||
}
|
}
|
||||||
break;
|
fflush(stdout);
|
||||||
case DO:
|
break;
|
||||||
case DONT:
|
case SB:
|
||||||
/* Do / Don't Negotation */
|
/* Begin Extended Option Mode */
|
||||||
opt = getchar();
|
sb_mode = 1;
|
||||||
if (!telnet_options[opt]) {
|
sb_len = 0;
|
||||||
/* We default to DONT */
|
memset(sb, 0, 1024);
|
||||||
telnet_options[opt] = DONT;
|
break;
|
||||||
}
|
case IAC:
|
||||||
send_command(telnet_options[opt], opt);
|
/* IAC IAC? That's probably not right. */
|
||||||
if (opt == ECHO) {
|
done = 2;
|
||||||
/* We don't really need this, as we don't accept input, but,
|
break;
|
||||||
* in case we do in the future, set our echo mode */
|
default:
|
||||||
do_echo = (i == DO);
|
break;
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
} else if (sb_mode) {
|
||||||
break;
|
/* Extended Option Mode -> Accept character */
|
||||||
case SB:
|
if (sb_len < 1023) {
|
||||||
/* Begin Extended Option Mode */
|
/* Append this character to the SB string,
|
||||||
sb_mode = 1;
|
* but only if it doesn't put us over
|
||||||
sb_len = 0;
|
* our limit; honestly, we shouldn't hit
|
||||||
memset(sb, 0, 1024);
|
* the limit, as we're only collecting characters
|
||||||
break;
|
* for a terminal type or window size, but better safe than
|
||||||
case IAC:
|
* sorry (and vulernable).
|
||||||
/* IAC IAC? That's probably not right. */
|
*/
|
||||||
done = 2;
|
sb[sb_len] = i;
|
||||||
break;
|
sb_len++;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (sb_mode) {
|
|
||||||
/* Extended Option Mode -> Accept character */
|
|
||||||
if (sb_len < 1023) {
|
|
||||||
/* Append this character to the SB string,
|
|
||||||
* but only if it doesn't put us over
|
|
||||||
* our limit; honestly, we shouldn't hit
|
|
||||||
* the limit, as we're only collecting characters
|
|
||||||
* for a terminal type or window size, but better safe than
|
|
||||||
* sorry (and vulernable).
|
|
||||||
*/
|
|
||||||
sb[sb_len] = i;
|
|
||||||
sb_len++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +425,7 @@ int main(int argc, char ** argv) {
|
|||||||
char * nterm = getenv("TERM");
|
char * nterm = getenv("TERM");
|
||||||
if (nterm)
|
if (nterm)
|
||||||
strcpy(term, nterm);
|
strcpy(term, nterm);
|
||||||
|
|
||||||
/* Also get the number of columns */
|
/* Also get the number of columns */
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
ioctl(0, TIOCGWINSZ, &w);
|
ioctl(0, TIOCGWINSZ, &w);
|
||||||
@ -390,7 +436,7 @@ int main(int argc, char ** argv) {
|
|||||||
for (k = 0; k < strlen(term); ++k) {
|
for (k = 0; k < strlen(term); ++k) {
|
||||||
term[k] = tolower(term[k]);
|
term[k] = tolower(term[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't want terminals wider than 80 columns */
|
/* We don't want terminals wider than 80 columns */
|
||||||
if(terminal_width > 80) terminal_width = 80;
|
if(terminal_width > 80) terminal_width = 80;
|
||||||
|
|
||||||
@ -548,40 +594,42 @@ int main(int argc, char ** argv) {
|
|||||||
/* Clear the screen */
|
/* Clear the screen */
|
||||||
printf("\033[H\033[2J\033[?25l");
|
printf("\033[H\033[2J\033[?25l");
|
||||||
|
|
||||||
/* Display the MOTD */
|
if (show_intro) {
|
||||||
int countdown_clock = 5;
|
/* Display the MOTD */
|
||||||
for (k = 0; k < countdown_clock; ++k) {
|
int countdown_clock = 5;
|
||||||
newline(3);
|
for (k = 0; k < countdown_clock; ++k) {
|
||||||
printf(" \033[1mNyancat Telnet Server\033[0m");
|
newline(3);
|
||||||
newline(2);
|
printf(" \033[1mNyancat Telnet Server\033[0m");
|
||||||
printf(" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m");
|
newline(2);
|
||||||
newline(2);
|
printf(" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m");
|
||||||
printf(" If things don't look right, try:");
|
newline(2);
|
||||||
newline(1);
|
printf(" If things don't look right, try:");
|
||||||
printf(" TERM=fallback telnet ...");
|
newline(1);
|
||||||
newline(2);
|
printf(" TERM=fallback telnet ...");
|
||||||
printf(" Or on Windows:");
|
newline(2);
|
||||||
newline(1);
|
printf(" Or on Windows:");
|
||||||
printf(" telnet -t vtnt ...");
|
newline(1);
|
||||||
newline(2);
|
printf(" telnet -t vtnt ...");
|
||||||
printf(" Problems? I am also a webserver:");
|
newline(2);
|
||||||
newline(1);
|
printf(" Problems? I am also a webserver:");
|
||||||
printf(" \033[1;34mhttp://miku.acm.uiuc.edu\033[0m");
|
newline(1);
|
||||||
newline(2);
|
printf(" \033[1;34mhttp://miku.acm.uiuc.edu\033[0m");
|
||||||
printf(" This is a telnet server, remember your escape keys!");
|
newline(2);
|
||||||
newline(1);
|
printf(" This is a telnet server, remember your escape keys!");
|
||||||
printf(" \033[1;31m^]quit\033[0m to exit");
|
newline(1);
|
||||||
newline(2);
|
printf(" \033[1;31m^]quit\033[0m to exit");
|
||||||
printf(" Starting in %d... \n", countdown_clock-k);
|
newline(2);
|
||||||
|
printf(" Starting in %d... \n", countdown_clock-k);
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
usleep(400000);
|
usleep(400000);
|
||||||
printf("\033[H"); /* Reset cursor */
|
printf("\033[H"); /* Reset cursor */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the screen again */
|
||||||
|
printf("\033[H\033[2J\033[?25l");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the screen again */
|
|
||||||
printf("\033[H\033[2J\033[?25l");
|
|
||||||
|
|
||||||
/* Store the start time */
|
/* Store the start time */
|
||||||
time_t start, current;
|
time_t start, current;
|
||||||
time(&start);
|
time(&start);
|
||||||
|
Loading…
Reference in New Issue
Block a user