Last active
June 11, 2023 18:34
-
-
Save wtv-411/6c3e4b4cfce495d8cc56fe634b2e35c5 to your computer and use it in GitHub Desktop.
De-tokenized TellyScript code originally generated for a WebTV (Classic) box
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This file contains a de-tokenized version of a TellyScript, a C-like language, | |
* generated by the WebTV/MSN TV service. The script in question was originally generated for | |
* an original WebTV Classic box (bf0/FCS) on May 27th, 1998, and was later decompiled using | |
* Andy McFadden's "detok" tool (https://gist.github.com/fadden/09b581dbb047945d3119048dc05e8bea) | |
* and cleaned up by me (wtv-411). The original, "compiled" version can be found as | |
* "bf0app_WTV_19980527.tok" on Archive.org here: https://archive.org/details/wtv-tellyscripts | |
* | |
* TellyScript is a scripting language designed by WebTV Networks. Its main purpose was | |
* to provide local phone numbers to be used for dial-up access by the WebTV and MSN TV | |
* line of internet set-top boxes (with a couple exceptions). TellyScript was designed by | |
* Andy Rubin and was based off of a scripting language he had previously written | |
* in college. There are only a couple WebTV/MSN TV clients known to not support the | |
* original TellyScript format. UltimateTV, a Windows CE-based satellite DVR built on WebTV | |
* technology, uses a variant of the format named DialScript, and the MSN TV 2 forgoes | |
* using TellyScript entirely. | |
* | |
* TellyScript is essentially a watered-down version of C and was designed to have | |
* the flexibility of a general programming language to have better control | |
* over a WebTV box's modem and the overall dialing process. Considering that the | |
* original WebTV boxes only had 2MB of ROM space, the TellyScript compiler couldn't | |
* support some features or data types that the original C language has, such as switch, | |
* bitwise OR, AND, and XOR, and the ability to initialize global variables. More information | |
* on the format can be found in the code of fadden's detok tool and here: | |
* https://wiki.webtv.zone/mediawiki/index.php/TellyScript | |
* | |
* All work from me involved renaming the appropriate variables and functions | |
* and adding comments to make the de-tokenized code more readable. Most of the | |
* variables were later swapped out for the names used in the original .tsf files used by | |
* the WebTV service to build TellyScripts (currently not available publicly to my knowledge). | |
* This code is being provided publicly for educational purposes, as it provides | |
* good insight into how TellyScripts work and interact with the WebTV/MSN TV hardware. | |
* | |
* Do note that this code cannot be compiled with a standard compiler, and would've | |
* been tokenized with a specialized TellyScript compiler on the WebTV service. | |
* A modern day equivalent of this has not been made yet as of writing. The newlines | |
* retained in the tokenized script will be kept in this code file for posterity. | |
*/ | |
/* START OF DETOKENIZED TELLYSCRIPT */ | |
int gDTERate; /* connection stats, set by ParseResult() */ | |
int gDCERate; | |
int gProtocol; | |
int gCompression; | |
int gConnected; /* set to 1 by ParseResult if we're considered connected */ | |
int gUsingOpenISP; /* are we an OpenISP script? */ | |
int gNVRAMMayBeInvalid; /* was the script sent down for a brain-dead download?*/ | |
WinkDTR() /* WNI hack to make the modem work properly. Fiddles with DTR. */ | |
{ | |
setdtr(0); | |
delay(30); | |
setdtr(1); | |
delay(30); | |
return 0; | |
} | |
StrLen(char *source) | |
{ | |
int count = 0; | |
while (*source++) | |
count++; | |
return count; | |
} | |
StrnCpy(char* dstStr, char* srcStr, int count) // WNI drop-in replacement for strncpy | |
{ | |
while (*srcStr) { | |
if (!count--) { | |
break; | |
} | |
*dstStr++ = *srcStr++; | |
} | |
if (count > 0) | |
*dstStr = 0; | |
return 0; | |
} | |
OStrChr(char *source, int value) | |
{ | |
char *orig = source; | |
while (*source != '\0') { | |
if (*source == value) { | |
return source - orig; | |
} | |
source++; | |
} | |
return -1; | |
} | |
SetDialingProgress(char *progressText, int percentage) | |
{ | |
setprogresstext(progressText); | |
setprogresspercentage(percentage); | |
setprogressdirty(1); | |
return 0; | |
} | |
// GetPhoneSettings - takes in int pointer as argument, returns pointer to phone settings buffer and sets int pointer to FONE version | |
GetPhoneSettings(int *pSettingsVersion) | |
{ | |
char *fonePtr; | |
int *foneLength; | |
int *magic; | |
int *rom_size = 0xbf00000c; // Pointer @ 0xbf00000c that reads the ROM size of the WebTV/MSN TV box's | |
// boot(?) ROM defined in its header | |
int *foneAddrEnd; | |
*pSettingsVersion = 0; | |
if (version() >= 9 || gNVRAMMayBeInvalid) { // is version >= 9 or is our NVRAM corrupted? | |
*pSettingsVersion = version(); | |
return getphonesettings(); // return data from built-in getphonesettings function | |
} | |
if (*rom_size == 0x80000) { // is the box ROM a 2MB rom? | |
fonePtr = 0xbf1fc000; // set FONE pointer to address 0xbf1fc000 | |
foneAddrEnd = 0xbf200000; // set pointer of end of data to address 0xbf200000 | |
} else if (*rom_size == 0x100000) { // else, if it's a 4MB rom... | |
fonePtr = 0xbf3fc000; // set the FONE pointer addresses accordingly | |
foneAddrEnd = 0xbf400000; | |
} else { | |
printf("TellyScript: couldn't determine size of ROM!"); | |
return 0; | |
} | |
fonePtr = fonePtr + 16; // advance 16 bytes in FONE data memory. skips past NVRAM header | |
while ((fonePtr + 9) < foneAddrEnd) { // read until end of ROM area | |
foneLength = fonePtr; | |
magic = fonePtr + 4; // set pointer to magic bytes 4 bytes after the FONE pointer | |
if (*magic == 0x464f4e45/*FONE*/) { | |
if (*foneLength == 105) { | |
*pSettingsVersion = 5; | |
} else if (*foneLength == 172) { | |
*pSettingsVersion = 8; | |
} else if (*foneLength == 336) { | |
*pSettingsVersion = 9; | |
} else if (*foneLength == 344) { | |
*pSettingsVersion = 11; | |
} else { | |
*pSettingsVersion = version(); | |
} | |
printf("TellyScript: FONE @ %x, len=%d, version=%d", | |
fonePtr + 8, *foneLength, *pSettingsVersion); | |
if (*pSettingsVersion == version()) { | |
return getphonesettings(); | |
} else { | |
return fonePtr + 8; | |
} | |
} | |
fonePtr = fonePtr + *foneLength + 8; /* advance pointer in FONE by the length plus 8 */ | |
fonePtr = fonePtr - (fonePtr % 4); /* make sure pointer address is a multiple of 4 */ | |
} | |
*pSettingsVersion = version(); | |
return getphonesettings(); | |
} | |
CheckFor56KAndS220(int *has56K, int *s220) | |
{ | |
char modemResult[32]; | |
flush(); | |
sendstr("ATI3\r"); | |
printf("TellyScript: SENT ATI3"); | |
getline(modemResult, 31, 300); | |
getline(modemResult, 31, 300); | |
printf("TellyScript: firmware query returned '%s'", modemResult + 1); | |
modemResult[21] = 0; | |
*has56K = 0; | |
if (strcmp(modemResult + 1, "V1.001_WEBTV-K56_DLP") == 0) { /* Check if our WebTV modem is 56K */ | |
*has56K = 1; /* if so, set the has56K variable accordingly */ | |
} | |
flush(); | |
sendstr("ATS220=0\r"); | |
printf("TellyScript: SENT ATS220=0"); | |
getline(modemResult, 31, 300); | |
getline(modemResult, 31, 300); | |
printf("TellyScript: S220 test returned '%s'", modemResult + 1); | |
*s220 = 0; | |
if (strcmp(modemResult + 1, "OK") == 0) { | |
*s220 = 1; | |
} | |
return 0; | |
} | |
SetupModemConfig(char *staticConfigBuf, char *dynamicConfigBuf) | |
{ | |
int foneVersion; | |
char *phoneSettings = getphonesettings(); // phone settings data | |
char *fone = GetPhoneSettings(&foneVersion); // get FONE version from ROM | |
char audibleDialing = phoneSettings[97]; | |
char waitForTone = phoneSettings[101]; | |
char useCallWaitingHack = phoneSettings[103]; | |
char dialSpeed = phoneSettings[104]; | |
char cwSensitivity = fone[105]; | |
char *s220Value, *cwValue = "14"; | |
int has56K, hasS220; | |
enablemodem(); | |
setflowcontrol(3); | |
setbaud(57600); // from base.tsf: "meaningless except for Mac simulator" | |
// if either the modem command or getting the modem details fail (the latter should not happen), then return error | |
if (SendAndWaitForOK("AT&D2V1E0\r", "OK")) | |
return 3; /* kTellyConfigurationError */ | |
if (CheckFor56KAndS220(&has56K, &hasS220)) | |
return 3; /* kTellyConfigurationError */ | |
if (has56K) { | |
printf("TellyScript: found v1.0 K56 firmware, disabling 56K"); | |
strcpy(staticConfigBuf, "AT+MS=11,1"); // copy "AT+MS=11,1" to static config buffer | |
} else { | |
strcpy(staticConfigBuf, "AT"); //copy "AT" to static config | |
} | |
strcat(staticConfigBuf, "S38=0S30=180S95=36S11=60&D2V1E0L3&Q5&K3\r"); | |
strcpy(dynamicConfigBuf, "ATV0"); // copy "ATV0" to dynamic config buffer | |
if (audibleDialing && (connectingwithvideoad() != 1)) { // enable audible dialing only if we aren't connecting with | |
// a video ad playing (WebTV Plus only) | |
strcat(dynamicConfigBuf, "M1"); // enable audible dialing | |
} else { | |
strcat(dynamicConfigBuf, "M0"); // turn audible dialing off (use WebTV dialing music) | |
} | |
if (waitForTone) { | |
strcat(dynamicConfigBuf, "S6=10X4"); // sets S6 register - "Wait Time before Blind Dialing" | |
} else { | |
strcat(dynamicConfigBuf, "S6=4X3"); | |
} | |
if (foneVersion >= 7) { | |
if (useCallWaitingHack) { | |
if (cwSensitivity == 1) { | |
cwValue = "113"; | |
} else if (cwSensitivity == 2) { | |
cwValue = "116"; | |
} else if (cwSensitivity == 3) { | |
cwValue = "88"; | |
} else if (cwSensitivity == 4) { | |
cwValue = "92"; | |
} else { | |
cwValue = "92"; | |
} | |
} | |
} else { | |
if (cwHack) cwValue = "92"; | |
} | |
printf("TellyScript: vers=%d/%d, cw-hack=%d, cw-sens=%d, setting S10 to %s", | |
version(), foneVersion, cwHack, cwSensitivity, cwValue); | |
strcat(dynamicConfigBuf, "S10="); | |
strcat(dynamicConfigBuf, cwValue); | |
if (hasS220) { | |
if (cwSensitivity == 1) { | |
s220Value = "32"; | |
} else if (cwSensitivity == 2) { | |
s220Value = "21"; | |
} else if (cwSensitivity == 3) { | |
s220Value = "11"; | |
} else { | |
s220Value = "1"; | |
} | |
printf("TellyScript: setting S220=%s", s220Value); | |
strcat(dynamicConfigBuf, "S220="); | |
strcat(dynamicConfigBuf, s220Value); | |
} else { | |
printf("TellyScript: not setting S220"); | |
} | |
if (dialSpeed == 0) { | |
strcat(dynamicConfigBuf, "S11=200&P1"); | |
} else if (dialSpeed == 1) { | |
strcat(dynamicConfigBuf, "S11=110&P1"); | |
} else if (dialSpeed == 2) { | |
strcat(dynamicConfigBuf, "S11=60&P3"); | |
} else if (dialSpeed == 3) { | |
strcat(dynamicConfigBuf, "S11=1&P3"); | |
} | |
strcat(dynamicConfigBuf, "\r"); | |
setwindowsize(3); | |
return 0; | |
} | |
GetPrefix(char *prefix, int isLocal) | |
{ | |
int foneVersion; | |
char *phoneSettings = getphonesettings(); | |
char *extendedSettings = GetPhoneSettings(&foneVersion); | |
char *callWaitingPrefix = &phoneSettings[0]; | |
char *dialOutsidePrefix = &phoneSettings[32]; | |
char disableCallWaiting = phoneSettings[98]; | |
char dialOutsideLine = phoneSettings[99]; | |
char *ldPrefix = &extendedSettings[140]; | |
prefix[0] = 0; | |
if (disableCallWaiting) | |
strcat(prefix, callWaitingPrefix); | |
if (foneVersion >= 8) { | |
if (ldPrefix[0] && !isLocal) { | |
printf("TellyScript: Using LD prefix"); | |
strcat(prefix, ldPrefix); | |
strcat(prefix, ","); | |
} else { | |
if (dialOutsideLine) { | |
strcat(prefix, dialOutsidePrefix); | |
strcat(prefix, ","); | |
} | |
} | |
} else { | |
if (dialOutsideLine) { | |
strcat(prefix, dialOutsidePrefix); | |
strcat(prefix, ","); | |
} | |
} | |
return 0; | |
} | |
SendAndWaitForOK(char *str, char *okstr) | |
{ | |
int retries = 0; | |
while (retries++ < 4) { | |
flush(); | |
sendstr(str); | |
if (waitfor(okstr, StrLen(okstr), 120)) { // Check if we got the expected response | |
printf("TellyScript: SENT config string '%s'", str); | |
break; | |
} else { | |
printf("TellyScript: TIMEOUT waiting for OK (str='%s')", str); | |
WinkDTR(); | |
} | |
} | |
if (retries >= 4) { | |
printf("TellyScript: Couldn't get '%s' from modem", okstr); | |
setdtr(0); | |
return 3; | |
} | |
return 0; | |
} | |
InitModem(char *staticConfig, char *dynamicConfig) | |
{ | |
setstatus(6); /* kTellyInitializingModem */ | |
ShowPreparingToCall(13); | |
WinkDTR(); | |
if (SendAndWaitForOK(staticConfig, "OK")) { | |
setdtr(0); | |
return 3; /* kTellyConfigurationError */ | |
} | |
if (SendAndWaitForOK(dynamicConfig, "0")) { | |
setdtr(0); | |
return 3; /* kTellyConfigurationError */ | |
} | |
setforcehook(1); | |
return (0); | |
} | |
ParseResult(int result) | |
{ | |
int returnCode = 0; | |
char *comment = ""; | |
if (result == 0) /* OK */ | |
{ | |
comment = " OK"; | |
returnCode = 1; /* okay */ | |
} | |
else if (result == 3) /* NO CARRIER */ | |
{ | |
comment = "NO CARRIER"; | |
returnCode = 12; /* kTellyNoCarrier */ | |
} | |
else if (result == 6) /* NO DIALTONE */ | |
{ | |
comment = "NO DIALTONE"; | |
returnCode = 5; /* kTellyNoDialtone */ | |
} | |
else if (result == 7) /* BUSY */ | |
{ | |
comment = "BUSY"; | |
returnCode = 7; /* kTellyBusy */ | |
} | |
else if (result == 8) /* NO ANSWER */ | |
{ | |
comment = "NO ANSWER"; | |
returnCode = 6; /* kTellyNoAnswer */ | |
} | |
else if (result >= 18 && result <= 19) /* CONNECT 57600 and 115200 */ | |
{ | |
comment = "Connected!"; | |
gConnected = 1; | |
gDTERate = 57600*(result - 17); | |
} | |
else if (result == 20) /* CONNECT 230400 */ | |
{ | |
comment = "Connected!"; | |
e = 1; | |
gDTERate = 230400; | |
} | |
else if (result >= 47 && result <= 51) /* CARRIER 2400 - CARRIER 12000 */ | |
{ | |
gDTERate = 2400*(result - 46); | |
returnCode = 14; /* kTellyVerySlowConnect */ | |
} | |
else if (result >= 52 && result <= 58) /* CARRIER 14400 - CARRIER 28800 */ | |
{ | |
gDCERate = 2400*(result - 46); | |
} | |
else if (result == 66) /* COMPRESSION: CLASS 5 */ | |
{ | |
gCompression = 1; | |
} | |
else if (result == 67) /* COMPRESSION: V.42bis */ | |
{ | |
gCompression = 2; | |
} | |
else if (result == 69) /* COMPRESSION: NONE */ | |
{ | |
gCompression = 0; | |
} | |
else if (result == 76) /* PROTOCOL: NONE */ | |
{ | |
gProtocol = 0; | |
} | |
else if (result == 77) /* PROTOCOL: LAPM */ | |
{ | |
gProtocol = 1; | |
} | |
else if (result == 78 || result == 60) /* CARRIER 31200 */ | |
{ | |
gDCERate = 31200; | |
} | |
else if (result == 79 || result == 65) /* CARRIER 33600 */ | |
{ | |
gDCERate = 33600; | |
} | |
else if (result == 80) /* PROTOCOL: ALT */ | |
{ | |
gProtocol = 2; | |
} | |
else if (result == 81) /* PROTOCOL: ALT-CELLULAR */ | |
{ | |
gProtocol = 3; | |
} | |
else if (result >= 150 && result <= 162) /* CARRIER 32000 - 56000 (K56) */ | |
{ | |
gDCERate = 2000*(result - 134); | |
} | |
else | |
{ | |
printf("TellyScript: ParseResult -- %d unknown", result); | |
returnCode = 9; /* kTellyUnknown */ | |
} | |
printf("TellyScript: ParseResult -- %d %s (retcode=%d)", result, | |
comment, returnCode); | |
return returnCode; | |
} | |
SendAccessNumberToModem(char *accessNumberToDial, int isLocal) | |
{ | |
int foneVersion; | |
char *phoneSettings = getphonesettings(); | |
char *fone = GetPhoneSettings(&foneVersion); | |
char *accessNumberSettings = &phoneSettings[64]; | |
char usePulseDialing = phoneSettings[96]; | |
char brokenPBX = fone[106]; | |
int tollFree, theDollar; | |
char prefixBuffer[64]; | |
char *prefixStr; | |
char *afterDollar; | |
char buffer[32]; | |
if (gUsingOpenISP) { | |
strcpy(buffer, "ISP-"); | |
StrnCpy(buffer + 4, accessNumberToDial, 31 - 4); | |
} else { | |
StrnCpy(buffer, accessNumberToDial, 31); | |
} | |
buffer[31] = 0; | |
setworkingnumber(buffer); | |
tollFree = IsTollFree(accessNumberToDial); | |
theDollar = OStrChr(accessNumber, '$'); // Find "$" in phone number | |
if (theDollar >= 0) { | |
strcpy(buffer, accessNumber); | |
afterDollar = buffer + theDollar + 1; | |
buffer[theDollar] = 0; | |
} | |
if (foneVersion >= 8 && brokenPBX && | |
(!accessNumber[0] || theDollar >= 0)) | |
{ | |
if (DoStripLeadingDigit(accessNumberToDial)) { | |
printf("TellyScript: BrokenPBX set, stripping leading digit"); | |
accessNumberToDial++; // increase position in access number | |
} | |
} | |
if (usePulseDialing) { | |
strcpy(prefixBuffer, "ATDP"); | |
} else { | |
strcpy(prefixBuffer, "ATDT"); | |
} | |
prefixStr = prefixBuffer + 4; | |
GetPrefix(prefixStr, isLocal); | |
setstatus(7); /* kTellyHandshake */ | |
if (gUsingOpenISP) { | |
ShowDialingNumber(prefixStr, accessNumberToDial, 26); | |
} else if (version() >= 8) { | |
if (accessNumber[0] && theDollar < 0) { // If we didn't find "$" in the phone number stored | |
// in NVRAM, we have an override number | |
ShowDialingAccessNumberOverride(prefixStr, accessNumberToDial, 26); | |
} else if (tollFree) { | |
ShowDialingWebTV(26); | |
} else { | |
ShowDialingNumber(prefixStr, accessNumberToDial, 26); | |
} | |
} else { | |
ShowDialingWebTV(26); | |
} | |
if ((accessNumberToDial[0] != 'A') && (accessNumberToDial[0] != 'a')) { | |
sendstr(prefixBuffer); | |
printf("TellyScript: SENT prefix '%s'", prefixBuffer); | |
} | |
if (theDollar < 0) { | |
sendstr(accessNumberToDial); | |
printf("TellyScript: SENT number '%s'", accessNumber); | |
} else { | |
sendstr(buffer); | |
sendstr(accessNumberToDial); | |
sendstr(afterDollar); | |
printf("TellyScript: SENT fancy '%s' '%s' '%s'", | |
buffer, accessNumberToDial, afterDollar); | |
} | |
sendstr(";\r"); | |
flush(); | |
return 0; | |
} | |
WaitForConnect() | |
{ | |
char *phoneSettings = getphonesettings(); | |
char audibleDialing = phoneSettings[97]; | |
char modemResult[32]; | |
int i, result, count; | |
i = 0; | |
gConnected = 0; | |
while (!gConnected && i < 6) { | |
count = getline(modemResult, 31, 4200); | |
i++; | |
if (count == 0) { // Modem response timed out | |
printf("TellyScript: TIMEOUT waiting for modem result"); | |
setdtr(0); | |
if (i == 1) | |
return 4; /* kTellyDialingError */ | |
else | |
return 8; /* kTellyHandshakeFailure */ | |
} | |
result = ParseResult(atoi(modemResult)); | |
if (result == 1) { | |
if (i == 1) { | |
sendstr("ATD\r"); | |
if (!audibleDialing) { | |
delay(180); | |
} | |
ShowWaitingToConnect(39); | |
result = 0; | |
} else { | |
setdtr(0); | |
printf("TellyScript: got '%s' at odd time", modemResult); | |
return 8; /* kTellyHandshakeFailure */ | |
} | |
} | |
if (result != 0) { | |
setdtr(0); | |
if (result == 12 && i > 2) { | |
return 8; /* kTellyHandshakeFailure */ | |
} | |
return result; | |
} | |
if (i == 2) { | |
setstatus(2); /* kTellyCarrier */ | |
if (f) { | |
ShowISPAnswering(52); | |
} else { | |
ShowWebTVAnswering(52); | |
} | |
} | |
} | |
printf("TellyScript: dterate=%d, dcerate=%d, protocol=%d, compression=%d", | |
gDTERate, gDCERate, gProtocol, gCompression); | |
setconnectionstats(gDTERate, gDCERate, gProtocol, gCompression); | |
return 0; | |
} | |
DialIAP(char *staticConfig, char *dynamicConfig, char *iapName, char *number, | |
int isLocal, int *pResult) | |
{ | |
*pResult = InitModem(staticConfig, dynamicConfig); | |
if (*pResult != 0) | |
return 2; | |
gDTERate = gDCERate = gProtocol = gCompression = 0; | |
printf("TellyScript: Calling %s/%s", iapName, number); | |
SendAccessNumberToModem(number, isLocal); | |
*pResult = WaitForConnect(); | |
if (*pResult) | |
printf("TellyScript: dialing failure, result=%d", *pResult); | |
if (*pResult == 4 || *pResult == 5) { | |
return 2; | |
} else if (*pResult) { | |
return 1; | |
} | |
return 0; | |
} | |
LoginWithPAPCreds(char *userNameBase, char *fixedPassword) // originally named PAPChat by WebTV Networks - initiates PAP login once the box is able to dial into an access point | |
{ | |
char *serial = getserialnumber(); | |
char username[48]; | |
char password[48]; | |
sprintf(username, userNameBase, serial); // format username string with serial number from SSID, and | |
// put it in username buffer | |
/* | |
* If fixedPassword is 0 or 1, then set the PAP password as the | |
* FCS16 value (proprietary WebTV CRC-like checksum) of the box's | |
* serial number. | |
* | |
* A JavaScript implementation of the FCS16 algorithm can be found | |
* here: https://webtv.zone/1800gen.html | |
*/ | |
if (fixedPassword == 0) { | |
sprintf(password, "%d", computefcs(serial)); | |
} else if (fixedPassword == 1) { | |
sprintf(password, "%08d", computefcs(serial)); | |
} else { | |
strcpy(password, fixedPassword); | |
} | |
printf("TellyScript: Using PAP with '%s'/'%s'", username, password); | |
setusername(username); | |
setpassword(password); | |
setpapmode(1); | |
setstatus(5); /* kNegotiatingPPP */ | |
ShowConnecting(88); | |
if (!startppp()) { | |
setdtr(0); | |
if (getpppresult() == 3) { | |
printf("TellyScript: PAP authentication failure"); | |
return 10; | |
} | |
printf("TellyScript: PPP negotiation failed"); | |
return 11; | |
} | |
printf("TellyScript: Link connected"); | |
setstatus(1); /* kTellyConnected */ | |
if (stack() < 0x200) { | |
ShowStackLow(100); | |
} else if (f) { | |
ShowConnectedToOpenISP(100); | |
} else { | |
ShowConnectedToWebTV(100); | |
} | |
return 0; | |
} | |
/* | |
* Unused in this specific script - determines the time on the WebTV/MSN TV box for | |
* "poptimized" TellyScripts to choose an access number based on the month, | |
* day of the week, or hour | |
*/ | |
WhatTimeIsIt(int* pMinute, int* pHour, int* pMonth, int* pYear, int* pDayOfWeek) | |
{ | |
int when, tmpyear; | |
parsesystemtime(7776000); /* from base.tsf: "90 days after Jan 1 1970" */ | |
tmpyear = getyear(); | |
when = getdatetimelocal(); | |
parsesystemtime(when); | |
if (tmpyear != 1970 || when < 7776000) { // Clock got reset from power loss, or the box is an old Classic (bf0/FCS) and is running in boot ROM mode | |
printf("TellyScript: time not available %d/%d", tmpyear, when); | |
*pDayOfWeek = 3; /* Set the time to Wed, Jan 1, 1970 at 7 PM */ | |
*pHour = 19; | |
*pMinute = 0; | |
*pMonth = 1; | |
*pYear = 1970; | |
return 1; | |
} | |
*pDayOfWeek = getdayofweek(); /* 0-6 */ | |
*pHour = gethour(); /* 0-23 */ | |
*pMinute = getminute(); /* 0-60 */ | |
*pMonth = getmonth(); /* 1-12 */ | |
*pYear = getyear(); | |
return 0; | |
} | |
DialByIndex(char* staticConfig, char* dynamicConfig, char* sequence) /* Attempts to dial all numbers in a sequence */ | |
{ | |
int status, err, nextNumber, sequenceLen, idx; | |
if (version() >= 8) { | |
nextNumber = getconnectretrycount(); | |
} else { | |
nextNumber = 0; | |
} | |
sequenceLen = StrLen(sequence); | |
printf("TellyScript: next=%d, seqLen=%d", nextNumber, sequenceLen); | |
err = 13; | |
for (idx = nextNumber;idx < sequenceLen;idx++) { | |
status = DialIndexedPOP(staticConfig, dynamicConfig, sequence[idx], | |
idx, &err); | |
if (status == 0) { | |
err = DoPAPLoginBasedOnPOP(popList[idx]); | |
if (!err || idx == sequenceLen - 1) { | |
return err; | |
} else { | |
dialerror(err); | |
} | |
} else if (status == 2 || idx == sequenceLen - 1) { | |
return err; | |
} else { | |
dialerror(err); | |
} | |
} | |
return err; | |
} | |
main() | |
{ | |
char *phoneSettings = getphonesettings(); | |
char *accessNumber = &phoneSettings[64]; | |
char staticConfig[80]; | |
char dynamicConfig[80]; | |
int start = ticks(); | |
int err, result = 0; | |
err = InitTellyScript(); | |
if (err) | |
return err; | |
err = SetupModemConfig(staticConfig, dynamicConfig); | |
if (err) | |
return err; | |
setprogressmode(1); /* from base.tsf: "take control of the status bar (version >= 8)" */ | |
setfullpopnumber(""); // clear POP number and variables for OpenISP and gNVRAMMayBeInvalid | |
gUsingOpenISP = 0; | |
gNVRAMMayBeInvalid = 0; | |
if (accessNumber[0] && OStrChr(accessNumber, '$') < 0) { | |
result = AccessDial(staticConfig, dynamicConfig, accessNumber); | |
if (result == 10) | |
result = 15; /* BadPasswordNR */ | |
} else { | |
result = PatternDial(staticConfig, dynamicConfig); | |
if (result == 10) | |
result = 15; /* BadPasswordNR */ | |
} | |
if (!result) { | |
printf("TellyScript: success, in %d seconds", | |
(ticks() - start) / 60); | |
return 2; /* kTellyLinkConnected */ | |
} else { | |
setconnectretrycount(0); /* from base.tsf: "temporary fix for 1.3.x" */ | |
printf("TellyScript: failure #%d, in %d seconds", result, | |
(ticks() - start) / 60); | |
setdtr(0); | |
return result; | |
} | |
} | |
IsTollFree(char *numberToDial) | |
{ | |
if ((numberToDial[1] == '8' && numberToDial[2] == '0' && numberToDial[3] == '0') || | |
(numberToDial[1] == '8' && numberToDial[2] == '8' && numberToDial[3] == '8')) | |
{ | |
return 1; | |
} | |
return 0; | |
} | |
DoStripLeadingDigit(char *numberToDial) | |
{ | |
if (*numberToDial == '1') | |
return 1; | |
else | |
return 0; | |
} | |
ShowPreparingToCall(int percent) | |
{ | |
SetDialingProgress("Preparing to call", percent); | |
} | |
ShowDialingNumber(char *wa, char *accessNumber, int percent) | |
{ | |
char message[128]; | |
sprintf(message, "Dialing %s%s", wa, accessNumber); | |
SetDialingProgress(message, percent); | |
} | |
ShowDialingAccessNumberOverride(char *wa, char *accessNumber, int percent) | |
{ | |
char message[128]; | |
sprintf(message, "Dialing A/N %s%s", wa, accessNumber); | |
SetDialingProgress(message, percent); | |
} | |
ShowDialingWebTV(int percent) | |
{ | |
SetDialingProgress("Dialing WebTV...", percent); | |
} | |
ShowWaitingToConnect(int percent) | |
{ | |
SetDialingProgress("Waiting to connect", percent); | |
} | |
ShowISPAnswering(int percent) | |
{ | |
SetDialingProgress("ISP answering", percent); | |
} | |
ShowWebTVAnswering(int percent) | |
{ | |
SetDialingProgress("WebTV answering", percent); | |
} | |
ShowConnecting(int percent) | |
{ | |
SetDialingProgress("Connecting", percent); | |
} | |
ShowConnectedToOpenISP(int percent) | |
{ | |
SetDialingProgress("Connected to your ISP", percent); | |
} | |
ShowConnectedToWebTV(int percent) | |
{ | |
SetDialingProgress("Connected to WebTV", percent); | |
} | |
ShowStackLow(int percent) | |
{ | |
SetDialingProgress("Warning: stack low", percent); | |
} | |
PAPLogin_artemis() // WebTV ISP | |
{ | |
return LoginWithPAPCreds("wtv_%s", 0); | |
} | |
PAPLogin_cnc() | |
{ | |
return LoginWithPAPCreds("%s!webtv", 0); | |
} | |
PAPLogin_cnc2() | |
{ | |
return LoginWithPAPCreds("%s@usage.webtv.net", 0); | |
} | |
PAPLogin_unk1() | |
{ | |
return LoginWithPAPCreds("UTV/%s", 0); | |
} | |
PAPLogin_uunet() | |
{ | |
return LoginWithPAPCreds("WTV/%s", 0); | |
} | |
InitTellyScript() | |
{ | |
printf("TellyScript: base.tsf version 49 (ANI=123-456-7890)"); | |
setnameservice(0xcf4f238d, 0xcf4f238e); | |
setani("123-456-XXXX"); // Phone number that appears on "Have You Moved?" dialog box | |
setlocalpopcount(4); | |
gNVRAMMayBeInvalid = 0; | |
return 0; | |
} | |
DoPAPLoginBasedOnPOP(int popIdx) | |
{ | |
if (popIdx == '0') { | |
return PAPLogin_artemis(); | |
} else if (popIdx == '1') { | |
return PAPLogin_cnc(); | |
} else if (popIdx == '2') { | |
return PAPLogin_cnc(); | |
} else if (popIdx == '3') { | |
return PAPLogin_uunet(); | |
} else if (popIdx == '4') { | |
return PAPLogin_uunet(); | |
} | |
return 16; | |
} | |
DialIndexedPOP(char *staticConfig, char *dynamicConfig, int idx, int yb, | |
int *result) | |
{ | |
char *accessNumber, *provider, *pop = ""; | |
int isLocal; | |
if (idx == '0') { | |
pop = "800-610-8918"; | |
accessNumber = "18006108918"; | |
provider = "artemis"; | |
isLocal = 0; | |
} else if (idx == '1') { | |
pop = "256-519-4030"; | |
accessNumber = "12565194030"; | |
provider = "cnc"; | |
isLocal = 1; | |
} else if (idx == '2') { | |
pop = "256-519-4030"; | |
accessNumber = "5194030"; | |
provider = "cnc"; | |
isLocal = 1; | |
} else if (idx == '3') { | |
pop = "205-533-1663"; | |
accessNumber = "12055331663"; | |
provider = "uunetdan"; | |
isLocal = 1; | |
} else if (idx == '4') { | |
pop = "205-533-1663"; | |
accessNumber = "2055331663"; | |
provider = "uunetdan"; | |
isLocal = 1; | |
} else { | |
printf("BUG!"); | |
*result = 16; | |
return 2; | |
} | |
setfullpopnumber(pop); | |
return DialIAP(staticConfig, dynamicConfig, provider, accessNumber, isLocal, result); | |
} | |
PatternDial(char *staticConfig, char *dynamicConfig) | |
{ | |
return DialByIndex(staticConfig, dynamicConfig, "24130"); | |
} | |
AccessDial(char *staticConfig, char *dynamicConfig, char *accessNumber) | |
{ | |
int status, err, nextNumber; | |
if (version() >= 8) { | |
nextNumber = getconnectretrycount(); | |
} else { | |
nextNumber = 0; | |
} | |
printf("TellyScript: next=%d", nextNumber); | |
if (nextNumber) { | |
return 13; | |
} | |
status = DialIAP(staticConfig, dynamicConfig, | |
"-access-", accessNumber, 1, &err); | |
if (status) { | |
setdtr(0); | |
return resultCode; | |
} | |
err = PAPLogin_cnc(); | |
return err; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment