diff --git a/zefie_wtvp_minisrv/includes/ServiceDeps/wtv-1800/tellyscripts/bf0app/bf0app.prereg.template.txt b/zefie_wtvp_minisrv/includes/ServiceDeps/wtv-1800/tellyscripts/bf0app/bf0app.prereg.template.txt new file mode 100644 index 00000000..768a7c40 --- /dev/null +++ b/zefie_wtvp_minisrv/includes/ServiceDeps/wtv-1800/tellyscripts/bf0app/bf0app.prereg.template.txt @@ -0,0 +1,462 @@ +int dterate; +int dcerate; +int protocol; +int compression; + +parseResult(int result) +{ + int retcode = 0; + + printf("TellyScript: parseResult -- %d", result); + + if (result == 0) + { + retcode = 0; + } + else if (result == 1) + { + dterate = 300; + } + else if (result == 3) + { + printf("TellyScript: Got NO CARRIER"); + retcode = 8; + } + else if (result == 5) + { + dterate = 0x4b0; + } + else if (result == 6) + { + printf("TellyScript: Got NO DIALTONE"); + retcode = 5; + } + else if (result == 7) + { + printf("TellyScript: Got BUSY"); + retcode = 7; + } + else if (result == 8) + { + retcode = 7; + } + else if (result == 9) + { + dterate = 0x258; + } + else if (result == 10) + { + dterate = 0x960; + } + else if (result == 11) + { + dterate = 0x12c0; + } + else if (result == 12) + { + dterate = 0x2580; + } + else if (result == 13) + { + dterate = 0x1c20; + } + else if (result == 14) + { + dterate = 0x2ee0; + } + else if (result == 15) + { + dterate = 0x3840; + } + else if (result == 16) + { + dterate = 0x4b00; + } + else if (result == 17) + { + dterate = 0x9600; + } + else if (result == 18) + { + dterate = 0xe100; + } + else if (result == 19) + { + dterate = 0x1c200; + } + else if (result == 22) + { + printf("TellyScript: Got a CONNECT 75TX/1200RX and I don't know why"); + dterate = 75; + } + else if (result == 23) + { + printf("TellyScript: Got a CONNECT 75TX/1200RX and I don't know why"); + dterate = 0x4b0 + } + else if (result == 40) + { + dcerate = 300; + } + else if (result == 44) + { + printf("TellyScript: Got a CONNECT 75TX/1200RX and I don't know why"); + dcerate = 0x4b0; + } + else if (result == 45) + { + printf("TellyScript: Got a CONNECT 75TX/1200RX and I don't know why"); + dcerate = 0x4b0; + } + else if (result == 46) + { + dcerate = 0x4b0; + } + else if (result == 47) + { + dcerate = 0x960; + } + else if (result == 48) + { + dcerate = 0x12c0; + } + else if (result == 49) + { + dcerate = 0x1c20; + } + else if (result == 50) + { + dcerate = 0x2580; + } + else if (result == 51) + { + dcerate = 0x2ee0; + } + else if (result == 52) + { + dcerate = 0x3840; + } + else if (result == 53) + { + dcerate = 0x41a0; + } + else if (result == 54) + { + dcerate = 0x4b00; + } + else if (result == 55) + { + dcerate = 0x5460; + } + else if (result == 56) + { + dcerate = 0x5dc0; + } + else if (result == 57) + { + dcerate = 0x6720; + } + else if (result == 58) + { + dcerate = 0x7080; + } + else if (result == 59) + { + dcerate = 0x41a0; + } + else if (result == 61) + { + dcerate = 0x5460; + } + else if (result == 62) + { + dcerate = 0x5dc0; + } + else if (result == 63) + { + dcerate = 0x6720; + } + else if (result == 64) + { + dcerate = 0x7080; + } + else if (result == 66) + { + compression = 1; + } + else if (result == 67) + { + compression = 2; + } + else if (result == 69) + { + compression = 0; + } + else if (result == 76) + { + protocol = 0; + } + else if (result == 77) + { + protocol = 1; + } + else if (result == 78) + { + dcerate = 0x79e0; + } + else if (result == 79) + { + dcerate = 0x8340; + } + else if (result == 80) + { + protocol = 2; + } + else if (result == 81) + { + protocol = 3; + } + else if (result == 84) + { + dcerate = 0x8340; + } + else if (result == 91) + { + dcerate = 0x79e0; + } + else + { + printf("TellyScript: Unknown result code %d", result); + retcode = 9; + } + + return retcode; +} + +winkdtr() +{ + setdtr(0); + delay(30); + setdtr(1); + delay(30); +} + +main() +{ + int count, i, retries, result; + int start = ticks(); + int end; + char *number; + char buffer[32]; + char *settings = getphonesettings(); + char *accessNumber = &settings[64]; + char *dialOutsidePrefix = &settings[32]; + char *callWaitingPrefix = &settings[0]; + char usePulseDialing = settings[96]; + char audibleDialing = settings[97]; + char disableCallWaiting = settings[98]; + char dialOutsideLine = settings[99]; + char changedCity = settings[100]; + char waitForTone = settings[101]; + char hasCallWaiting = settings[102]; + char useCallWaitingHack = settings[103]; + char dialSpeed = settings[104]; + char numberToDial[32]; + char dialCommand[80]; + char *configurationCommand = "ATS38=0S30=180S95=36S11=60&D2V1E0L2&Q5&K3\r"; + char *defaultNumber = "%DialinNumber%"; + char *nvOverRide = getpreregnumber(); + char *secret = getsecret(); + char *serial_number = getserialnumber(); + char username[32]; + char password[32]; + + printf("TellyScript: 800 Registration Script 3.1-zefie"); + + + + + if (nvOverRide != 0) + { + defaultNumber = nvOverRide; + printf("TellyScript: Over-riding default preregistration number with %s from NVRAM", nvOverRide); + } + + + + if (accessNumber[0]) + strcpy(numberToDial, accessNumber); + else + strcpy(numberToDial, defaultNumber); + + + + strcpy(dialCommand, "ATV0"); + + + + if (audibleDialing) + strcat(dialCommand, "M1"); + else + strcat(dialCommand, "M0"); + + + + if (waitForTone) + strcat(dialCommand, "S6=10X4"); + else + strcat(dialCommand, "S6=4X3"); + + + + strcat(dialCommand, "S10=14"); + + + + if (dialSpeed == 0) + strcat(dialCommand, "S11=200"); + else if (dialSpeed == 1) + strcat(dialCommand, "S11=110"); + else if (dialSpeed == 2) + strcat(dialCommand, "S11=60"); + else if (dialSpeed == 3) + strcat(dialCommand, "S11=1"); + + + + if (usePulseDialing) + strcat(dialCommand, "DP"); + else + strcat(dialCommand, "DT"); + + + + if (disableCallWaiting) + { + strcat(dialCommand, callWaitingPrefix); + } + + + + if (dialOutsideLine) + { + strcat(dialCommand, dialOutsidePrefix); + strcat(dialCommand, ","); + } + + + + setwindowsize(3); + printf("TellyScript: TCP Window Size set to 3 (USR)."); + + enablemodem(); + + winkdtr(); + setflowcontrol(3); + setbaud(0xe100); + + setstatus(6); + retries = 0; + while (retries++ <= 2) + { + flush(); + + sendstr(configurationCommand); + if (waitfor("OK", 2, 120)) + { + printf("TellyScript: Configured modem."); + break; + } + else + { + printf("TellyScript: TIMEOUT waiting for OK"); + winkdtr(); + } + } + + if (retries > 3) + { + printf("TellyScript: Couldn't get OK from modem"); + setdtr(0); + return 3; + } + + setstatus(3); + + printf("TellyScript: Overriding exclusion circuit..."); + setforcehook(1); + + printf("TellyScript: Dialing %s...", numberToDial); + if ((numberToDial[0] != 65) && (numberToDial[0] != 97)) + sendstr(dialCommand); + sendstr(numberToDial); + + sendstr(";\r"); + + flush(); + + i = 0; + while (i++ < 4) + { + count = getline(buffer, 31, 0xe10); + + if (count == 0) + { + printf("TellyScript: TIMEOUT waiting for dial result."); + setdtr(0); + return 4; + } + + result = parseResult(atoi(buffer)); + if ((result == 0) && (i == 1)) + { + setstatus(7); + sendstr("ATD\r"); + } + + if (result != 0) + { + setdtr(0); + return result; + } + } + + printf("TellyScript: Setting NameServers: %DNSIP1%, %DNSIP2%"); + setnameservice(%DNS1%, %DNS2%); + + printf("TellyScript: dterate = %d, dcerate = %d, protocol = %d, compression = %d", + dterate, dcerate, protocol, compression); + setconnectionstats(dterate, dcerate, protocol, compression); + setstatus(2); + + sprintf(username, "wtv_%s", serial_number); + sprintf(password, "%d", computefcs(serial_number)); + + printf("TellyScript: Using '%s' for username", username); + printf("TellyScript: Using '%s' for password", password); + + setusername(username); + setpassword(password); + setpapmode(1); + setstatus(5); + + if (!startppp()) + { + setdtr(0); + if (getpppresult() == 3) + { + printf("TellyScript: PAP authentification failure"); + return 10; + } + + printf("TellyScript: PPP negotiation failed"); + return 8; + } + + printf("TellyScript: Link connected."); + setstatus(1); + + printf("TellyScript: total time = %d (seconds)", (ticks() - start) / 60); + + return 2; +} diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-1800/preregister.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-1800/preregister.js index b22884e4..731dc93f 100644 --- a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-1800/preregister.js +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-1800/preregister.js @@ -110,7 +110,8 @@ if (session_data.data_store.wtvsec_login) { prereg_contype = "text/tellyscript"; // if wtv-open-access: true then client expects OpenISP if (session_data.get("wtv-open-access")) file_path = wtvshared.getServiceDep("/wtv-1800/tellyscripts/bf0app/bf0app_OISP.tok", true); - else file_path = wtvshared.getServiceDep("/wtv-1800/tellyscripts/bf0app/bf0app_WTV_18006138199.tok", true); + else template_path = wtvshared.getServiceDep("/wtv-1800/tellyscripts/bf0app/bf0app.prereg.template.txt", true); + //else file_path = wtvshared.getServiceDep("/wtv-1800/tellyscripts/bf0app/bf0app_WTV_18006138199.tok", true); break; // the following are not yet zefie generated and may have an unknown username/password attached @@ -207,6 +208,7 @@ if (session_data.data_store.wtvsec_login) { } telly = new WTVTellyScript(file_read_data, 2); // 2 = Untokenized telly.setTemplateVars(minisrv_config.config.service_name, minisrv_config.services[service_name].dialin_number, minisrv_config.services[service_name].dns1ip, minisrv_config.services[service_name].dns2ip); + telly.minify(); telly.tokenize(); telly.pack(); sendToClient(socket, headers, telly.packed_data); diff --git a/zefie_wtvp_minisrv/includes/classes/WTVTellyScript.js b/zefie_wtvp_minisrv/includes/classes/WTVTellyScript.js index bd6f8a1e..6063fc28 100644 --- a/zefie_wtvp_minisrv/includes/classes/WTVTellyScript.js +++ b/zefie_wtvp_minisrv/includes/classes/WTVTellyScript.js @@ -36,6 +36,17 @@ const TellyScriptType = { DIALSCRIPT: 1, }; +const reservedKeywords = new Set([ + 'int', 'char', 'if', 'else', 'while', 'return', 'void', , 'delay', 'flush', 'break', + 'printf', 'atoi', 'main', 'setprogressmode', 'setprogresstext', 'setworkingnumber', + 'setprogresspercentage', 'setprogressdirty', 'strcpy', 'strcat', 'setwindowsize', + 'enablemodem', 'builtin_winkdtr', 'setflowcontrol', 'setbaud', 'setdtr', 'sendstr', + 'setusername', 'setpassword', 'setpapmode', 'startppp', 'getpppresult', 'ticks', + 'getpreregnumber', 'getserialnumber', 'getsecret', 'getphonesettings', 'setstatus', + 'sprintf', 'setconnectionstats', 'setforcehook', 'waitfor', 'setnameservice', + 'getline' +]); + class WTVTellyScriptTokenizer { constructor(rawData) { @@ -902,6 +913,128 @@ class WTVTellyScriptDetokenizer { } +class WTVTellyScriptMinifier { + // 1. Tokenization: Build the token array from raw text + tokenize(input) { + // Define token specs as pairs: [regex, tokenType] + const tokenSpecs = [ + [/^\s+/, 'WHITESPACE'], // Whitespace (skip) + [/^\/\/.*/, null], // Single-line comment (skip) + [/^\/\*[\s\S]*?\*\//, null], // Multi-line comment (skip) + // Keywords (update with your TellyScript keywords as needed) + [/^\b(int|char|if|else|while|return|void)\b/, 'KEYWORD'], + // Identifiers (variable and function names) + [/^\b[a-zA-Z_][a-zA-Z0-9_]*\b/, 'IDENTIFIER'], + // Hexadecimal numbers (e.g., 0xe100) + [/^0x[0-9a-fA-F]+/, 'NUMBER'], + // Decimal numbers + [/^\d+/, 'NUMBER'], + // String literals (supports escaped quotes) + [/^"([^"\\]|\\.)*"/, 'STRING'], + // Punctuation (parentheses, braces, commas, semicolons, etc.) + [/^[{};,\[\]\(\)]/, 'PUNCTUATION'], + // Operators (covers common operators; adjust as needed) + [/^(==|!=|<=|>=|[+\-*/=<>!&|%]+)/, 'OPERATOR'] + ]; + + const tokens = []; + let remaining = input; + + while (remaining.length > 0) { + let matched = false; + for (const [regex, tokenType] of tokenSpecs) { + const match = regex.exec(remaining); + if (match) { + matched = true; + const tokenValue = match[0]; + // Only include tokens with a type (skip whitespace/comments) + if (tokenType) { + tokens.push({ type: tokenType, value: tokenValue }); + } + // Slice off the matched portion of the input + remaining = remaining.slice(tokenValue.length); + break; + } + } + if (!matched) { + throw new Error("Unexpected token: " + remaining[0]); + } + } + return tokens; + } + + detokenize(tokens) { + let output = ""; + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; + output += token.value; + + // Look ahead to the next token + if (i < tokens.length - 1) { + const nextToken = tokens[i + 1]; + // Insert a space if both tokens are of types that, if concatenated, could form a different valid token. + if (token.type === 'OPERATOR' && token.value === '=' && nextToken.type === 'OPERATOR' && nextToken.value === '&') { + output += " "; + } + if ((token.type === 'IDENTIFIER' || token.type === 'NUMBER') && + (nextToken.type === 'IDENTIFIER' || nextToken.type === 'NUMBER') || + token.type === 'KEYWORD') { + output += " "; + } + } + } + return output; + } + + // 2. Minification: Dynamically generate short names for variable identifiers + + // Helper: Convert a counter to a short name (0 -> "a", 1 -> "b", ... 26 -> "aa", etc.) + generateShortName(counter) { + let name = ''; + let n = counter; + do { + name = String.fromCharCode(97 + (n % 26)) + name; + n = Math.floor(n / 26) - 1; + } while (n >= 0); + return name; + } + + // Reserved keywords that should not be renamed (include any built-in function names too) + + minifyIdentifiers(tokens) { + const mapping = {}; // Map original identifier -> short name + let counter = 0; + + // First pass: Build mapping for each identifier that isn't a reserved keyword. + tokens.forEach(token => { + if (token.type === 'IDENTIFIER' && !reservedKeywords.has(token.value)) { + if (!(token.value in mapping)) { + mapping[token.value] = this.generateShortName(counter++); + } + } + }); + + // Second pass: Replace identifier token values with their short names. + tokens.forEach(token => { + if (token.type === 'IDENTIFIER' && mapping[token.value]) { + token.value = mapping[token.value]; + } + }); + + return tokens; + } + + + minify(tellyscript) { + // Tokenize the raw text + let tokens = this.tokenize(tellyscript.raw_data); +console.log(tokens) + // Minify identifier names + tokens = this.minifyIdentifiers(tokens); + return this.detokenize(tokens); + } +} + class WTVTellyScript { // --- TellyScript Class --- @@ -921,6 +1054,13 @@ class WTVTellyScript { this.process(data, dataState); } + minify() { + let minifier = new WTVTellyScriptMinifier(); + this.raw_data = minifier.minify(this); + this.tokenize(); + this.pack(); + } + ipToHex(ip) { const parts = ip.split('.'); if (parts.length !== 4) { @@ -934,7 +1074,8 @@ class WTVTellyScript { } num = (num << 8) | part; } - return "0x" + num.toString(16).toUpperCase(); + // Convert to unsigned 32-bit number before converting to hex + return "0x" + (num >>> 0).toString(16).toUpperCase(); } setTemplateVars(service_name, dialin_number, DNS1IP, DNS2IP) { diff --git a/zefie_wtvp_minisrv/test_prereg.js b/zefie_wtvp_minisrv/test_prereg.js index 8bf4258a..833f8806 100644 --- a/zefie_wtvp_minisrv/test_prereg.js +++ b/zefie_wtvp_minisrv/test_prereg.js @@ -9,7 +9,6 @@ const WTVTellyScript = require(classPath + "/WTVTellyScript.js") headers = `GET wtv-1800:/preregister wtv-client-serial-number: 9111111111111111 -wtv-client-rom-type: US-LC2-disk-0MB-8MB wtv-show-time-record: 1 wtv-request-type: primary wtv-system-cpuspeed: 166187148 @@ -22,7 +21,7 @@ wtv-connect-session-id: 7b662075 wtv-system-version: 7181 wtv-capability-flags: 10935ffc8f wtv-client-bootrom-version: 2046 -wtv-client-rom-type: US-LC2-disk-0MB-8MB +wtv-client-rom-type: bf0app wtv-system-chipversion: 51511296 User-Agent: Mozilla/4.0 WebTV/2.2.6.1 (compatible; MSIE 4.0) wtv-encryption: true diff --git a/zefie_wtvp_minisrv/test_telly2.js b/zefie_wtvp_minisrv/test_telly2.js new file mode 100644 index 00000000..886f4eb9 --- /dev/null +++ b/zefie_wtvp_minisrv/test_telly2.js @@ -0,0 +1,19 @@ +const process = require('process'); +const fs = require('fs'); +const path = require('path'); +const classPath = path.resolve(__dirname + path.sep + "includes" + path.sep + "classes" + path.sep) + path.sep; +const { WTVShared, clientShowAlert } = require(classPath + "/WTVShared.js"); +const WTVTellyScript = require(classPath + "/WTVTellyScript.js") +//const bf0app = classPath + "/../ServiceDeps/wtv-1800/tellyscripts/bf0app/bf0app_WTV_18006138199.tok" +//const tokened = fs.readFileSync(bf0app); +const LC2 = classPath + "/../ServiceDeps/wtv-1800/tellyscripts/LC2/LC2.prereg.template.txt"; +const tokened = fs.readFileSync(LC2); +console.log("OGTOK:", tokened) +var token = new WTVTellyScript(tokened, 2); +console.log("OGTOK Header:", token.packed_header); +token.setTemplateVars("Test", 5736666, "192.168.11.1", "8.8.8.8"); +console.log(token.raw_data); +token.tokenize(); +token.pack(); +token.minify(); +