From 4adc84b22d157d885ab628aebd628098a6f8f529 Mon Sep 17 00:00:00 2001 From: Rob Swindell <rob@synchro.net> Date: Sun, 15 May 2022 23:49:36 -0700 Subject: [PATCH] Implement svdm.ini file support to store settings and modem NVRAM e.g. AT&W writes the current settings to the [modem] section. --- src/vdmodem/vdmodem.c | 156 +++++++++++++++++++++++++++++++++++------- 1 file changed, 132 insertions(+), 24 deletions(-) diff --git a/src/vdmodem/vdmodem.c b/src/vdmodem/vdmodem.c index 93d1f29f0e..e3f0675ceb 100644 --- a/src/vdmodem/vdmodem.c +++ b/src/vdmodem/vdmodem.c @@ -29,9 +29,11 @@ #include <process.h> #include "genwrap.h" +#include "dirwrap.h" #include "gen_defs.h" #include "sockwrap.h" #include "telnet.h" +#include "ini_file.h" #define TITLE "Synchronet Virtual DOS Modem for Windows" #define VERSION "0.0" @@ -43,11 +45,14 @@ HANDLE hungup_event = INVALID_HANDLE_VALUE; // e.g. ATH0 HANDLE carrier_event = INVALID_HANDLE_VALUE; HANDLE rdslot = INVALID_HANDLE_VALUE; HANDLE wrslot = INVALID_HANDLE_VALUE; +str_list_t ini; +char ini_fname[MAX_PATH + 1]; union xp_sockaddr listening_interface; enum { RAW ,TELNET } mode; +char* modeNames[] = {"raw", "telnet", NULL}; struct { uint8_t local_option[0x100]; uint8_t remote_option[0x100]; @@ -65,12 +70,14 @@ struct { bool debug; bool terminate_on_disconnect; ulong data_rate; + bool server_echo; enum { ADDRESS_FAMILY_UNSPEC ,ADDRESS_FAMILY_INET ,ADDRESS_FAMILY_INET6 } address_family; } cfg; +char* addrFamilyNames[] = {"unspec", "ipv4", "ipv6", NULL}; static void dprintf(const char *fmt, ...) { @@ -93,6 +100,7 @@ void usage(void) const char* supported_cmds = "ADEHIMOQSVXZ&"; const char* string_cmds = "D"; +#define MAX_SAVES 20 struct modem { enum { INIT @@ -103,6 +111,8 @@ struct modem { char lf; char bs; char esc; + char save[MAX_SAVES][INI_MAX_VALUE_LEN]; + char last[INI_MAX_VALUE_LEN]; bool echo_off; bool numeric_mode; bool offhook; @@ -125,18 +135,6 @@ void newcmd(struct modem* modem) modem->buflen = 0; } -void init(struct modem* modem) -{ - memset(modem, 0, sizeof(*modem)); - modem->cr = '\r'; - modem->lf = '\n'; - modem->bs = '\b'; - modem->esc = '+'; - modem->ext_results = 4; - modem->dial_wait = 60; - modem->guard_time = 50; -} - ulong guard_time(struct modem* modem) { return modem->guard_time * 20; @@ -251,6 +249,58 @@ bool kbhit() return waiting != 0; } +void init(struct modem* modem) +{ + const char* section = "modem"; + memset(modem, 0, sizeof(*modem)); + modem->auto_answer = iniGetBool(ini, section, "auto_answer", FALSE); + modem->echo_off = !iniGetBool(ini, section, "echo", TRUE); + modem->quiet = iniGetBool(ini, section, "quiet", FALSE); + modem->numeric_mode = iniGetBool(ini, section, "numeric", FALSE); + modem->cr = (char)iniGetInteger(ini, section, "cr", '\r'); + modem->lf = (char)iniGetInteger(ini, section, "lf", '\n'); + modem->bs = (char)iniGetInteger(ini, section, "bs", '\b'); + modem->esc = (char)iniGetInteger(ini, section, "esc", '+'); + modem->ext_results = iniGetInteger(ini, section, "ext_results", 4); + modem->dial_wait = iniGetInteger(ini, section, "dial_wait", 60); + modem->guard_time = iniGetInteger(ini, section, "guard_time", 50); +} + +bool write_cfg(struct modem* modem) +{ + dprintf(__FUNCTION__); + const char* section = "modem"; + iniSetBool(&ini, section, "auto_answer", modem->auto_answer, /* style: */NULL); + bool result = false; + FILE* fp = iniOpenFile(ini_fname, /* create: */TRUE); + if(fp != NULL) { + if(iniWriteFile(fp, ini)) { + dprintf("Wrote config to: %s", ini_fname); + result = true; + } + iniCloseFile(fp); + } + return result; +} + +bool write_save(struct modem* modem, ulong savnum) +{ + char key[128]; + str_list_t ini; + + if(savnum >= MAX_SAVES) + return false; + SAFEPRINTF(key, "save%lu", savnum); + FILE* fp = iniOpenFile(ini_fname, /* create: */TRUE); + if(fp == NULL) + return false; + ini = iniReadFile(fp); + iniSetString(&ini, "modem", key, modem->save[savnum], /* style: */NULL); + bool result = iniWriteFile(fp, ini); + iniCloseFile(fp); + return result; +} + const char* protocol(enum mode mode) { switch(mode) { @@ -431,16 +481,22 @@ char* dial(struct modem* modem, const char* number) { struct addrinfo hints; struct addrinfo *res=NULL; - static char last[256]; char host[128]; char portnum[16]; uint16_t port = cfg.port; dprintf("dial(%s)", number); if(stricmp(number, "L") == 0) - number = last; - else - SAFECOPY(last, number); + number = modem->last; + else { + if(toupper(*number) == 'S' && IS_DIGIT(number[1])) { + char* p; + ulong val = strtoul(number+1, &p, 10); + if(val < MAX_SAVES && *p == '\0') + number = modem->save[val]; + } + SAFECOPY(modem->last, number); + } if(strncmp(number, "raw:", 4) == 0) { mode = RAW; number += 4; @@ -570,8 +626,10 @@ char* answer(struct modem* modem) if(mode == TELNET) { ZERO_VAR(telnet); - /* Disable Telnet Terminal Echo */ - request_telnet_opt(TELNET_WILL,TELNET_ECHO); + if(cfg.server_echo) { + /* Disable Telnet Terminal Echo */ + request_telnet_opt(TELNET_WILL,TELNET_ECHO); + } /* Will suppress Go Ahead */ request_telnet_opt(TELNET_WILL,TELNET_SUP_GA); } @@ -590,9 +648,31 @@ char* atmodem_exec(struct modem* modem) return error(modem); if(strchr(string_cmds, ch) == NULL) { if(ch == '&') { - p++; - ch = toupper(*p); // unused - ulong val = strtoul(p, &p, 10); // unused + ch = toupper(*p); + ulong val = strtoul(p + 1, &p, 10); // unused + switch(ch) { + case 'W': + resp = write_cfg(modem) ? ok(modem) : error(modem); + break; + case 'Z': + if(val >= MAX_SAVES) + return error(modem); + if(*p == '=') { + p++; + if(strcmp(p, "L") == 0) + p = modem->last; + SAFECOPY(modem->save[val], p); + return write_save(modem, val) ? ok(modem) : error(modem); + } + if(*p == '?' || strcmp(p, "L?") == 0) { + if(strcmp(p, "L?") == 0) + p = modem->last; + else + p = modem->save[val]; + sprintf(respbuf, "%c%s%c%c%s", modem->lf, p, modem->cr, modem->lf, ok(modem)); + return respbuf; + } + } continue; } // Numeric argument commands @@ -636,8 +716,10 @@ char* atmodem_exec(struct modem* modem) dprintf("S%lu = %lu", sreg, val); switch(sreg) { case 0: - if(val && listening_sock == INVALID_SOCKET) + if(val && listening_sock == INVALID_SOCKET) { + dprintf("Can't enable auto-answer when not in listening mode"); return error(modem); + } modem->auto_answer = val; break; case 1: @@ -707,8 +789,10 @@ char* atmodem_exec(struct modem* modem) } else { // string argument commands switch(ch) { case 'D': - if(sock != INVALID_SOCKET) + if(sock != INVALID_SOCKET) { + dprintf("Can't dial: Already connected"); return error(modem); + } if(*p == 'T' /* tone */|| *p == 'P' /* pulse */) p++; return dial(modem, p); @@ -837,7 +921,31 @@ int main(int argc, char** argv) return EXIT_FAILURE; } + // Default configuration values + cfg.server_echo = TRUE; cfg.port = IPPORT_TELNET; + cfg.address_family = ADDRESS_FAMILY_INET; + + ini = strListInit(); + SAFECOPY(ini_fname, argv[0]); + char* ext = getfext(ini_fname); + if(ext != NULL) + *ext = 0; + SAFECAT(ini_fname, ".ini"); + fprintf(stderr, "ini_fname = '%s'\n", ini_fname); + FILE* fp = iniOpenFile(ini_fname, /* create: */false); + if(fp != NULL) { + ini = iniReadFile(fp); + iniCloseFile(fp); + mode = iniGetEnum(ini, ROOT_SECTION, "mode", modeNames, mode); + cfg.port = iniGetShortInt(ini, ROOT_SECTION, "port", cfg.port); + cfg.node_num = iniGetInteger(ini, ROOT_SECTION, "node", cfg.node_num); + cfg.listen = iniGetBool(ini, ROOT_SECTION, "listen", cfg.listen); + cfg.debug = iniGetBool(ini, ROOT_SECTION, "debug", cfg.debug); + cfg.server_echo = iniGetBool(ini, ROOT_SECTION, "server_echo", cfg.server_echo); + cfg.data_rate = iniGetLongInt(ini, ROOT_SECTION, "rate", cfg.data_rate); + cfg.address_family = iniGetEnum(ini, ROOT_SECTION, "address_family", addrFamilyNames, cfg.address_family); + } for(; argn < argc; argn++) { char* arg = argv[argn]; @@ -931,7 +1039,7 @@ int main(int argc, char** argv) } const char* dropfile = "dosxtrn.env"; - FILE* fp = fopen(dropfile, "w"); + fp = fopen(dropfile, "w"); if(fp == NULL) { perror(dropfile); return EXIT_FAILURE; -- GitLab