SHOW:
|
|
- or go back to the newest paste.
| 1 | // BOF preprocessor bug prevent - insert me on top of your arduino-code | |
| 2 | #if 1 | |
| 3 | __asm volatile ("nop");
| |
| 4 | #endif | |
| 5 | /*----------------------------------------------------------------------------- | |
| 6 | ||
| 7 | *ALL RAM* BBS for Arduino | |
| 8 | by Allen C. Huffman ([email protected] / www.appleause.com) | |
| 9 | ||
| 10 | This is an experiment to see how easy it is to translate Microsoft BASIC to | |
| 11 | Arduino C. The translated C code is incredibly ugly and will be disturbing | |
| 12 | to most modern programmers. It was done just to see if it could be done, and | |
| 13 | what better thing to translate than a program that was also originally done | |
| 14 | just to see if it could be done -- a cassette based BBS package from 1983! | |
| 15 | ||
| 16 | About the *ALL RAM* BBS: | |
| 17 | ||
| 18 | The *ALL RAM* BBS System was writtin in 1983 for the Radio Shack TRS-80 | |
| 19 | Color Computer ("CoCo"). At this time, existing BBS packages for the CoCo
| |
| 20 | required "2-4 disk drives" to operate, so *ALL RAM* was created to prove | |
| 21 | a BBS could run from a cassette-based computer. Instead of using floppy | |
| 22 | disks to store the userlog and message base, they were contained entirely | |
| 23 | in RAM. The in-memory databases could be saved to cassette tape and | |
| 24 | reloaded later. | |
| 25 | ||
| 26 | The original BASIC source code is included in comments, followed by a very | |
| 27 | literal line-by-line translation to Arduino C. Remember, it's not a rewrite | |
| 28 | in C -- it's BASIC code done in C. | |
| 29 | ||
| 30 | Be warned. There be "gotos" ahead! | |
| 31 | ||
| 32 | References about memory saving: | |
| 33 | ||
| 34 | http://www.controllerprojects.com/2011/05/23/saving-ram-space-on-arduino-when-you-do-a-serial-printstring-in-quotes/ | |
| 35 | ||
| 36 | ||
| 37 | http://www.adafruit.com/blog/2008/04/17/free-up-some-arduino-sram/ | |
| 38 | ||
| 39 | 2013-04-02 0.0 allenh - Initial version with working userlog. | |
| 40 | 2013-04-03 1.0 allenh - Message base working. Core system fully functional. | |
| 41 | Preliminary support for Arduino Ethernet added. | |
| 42 | 2013-04-04 1.1 allenh - SD card support for loading/saving. | |
| 43 | 2013-04-05 1.2 allenh - Ethernet (telnet) support. | |
| 44 | 2013-04-06 1.3 allenh - Cleanup for posting to www.appleause.com | |
| 45 | 2013-04-09 1.4 allenh - Fixed a bug with INPUT_SIZE and input. | |
| 46 | 2013-04-12 1.5 allenh - Integration with new Telnet server code, misc fixes. | |
| 47 | -----------------------------------------------------------------------------*/ | |
| 48 | #include <avr/pgmspace.h> | |
| 49 | ||
| 50 | #define VERSION "1.5" | |
| 51 | ||
| 52 | // To enable SD card support, define the PIN used by SD.begin(x) | |
| 53 | //#define SD_PIN 4 | |
| 54 | ||
| 55 | // To enable Ethernet support, defined the PORT used by EthernetServer(PORT) | |
| 56 | //#define ENET_PORT 23 | |
| 57 | ||
| 58 | // NOTE: On smaller Arduinos (UNO), there is not enough Flash or RAM to have | |
| 59 | // both SD and Ethernet support at the same time. | |
| 60 | ||
| 61 | #if defined(SD_PIN) | |
| 62 | - | #include |
| 62 | + | #include <SD.h> |
| 63 | #endif | |
| 64 | ||
| 65 | #if defined(ENET_PORT) | |
| 66 | - | #include |
| 66 | + | #include <SPI.h> |
| 67 | - | #include |
| 67 | + | #include <Ethernet.h> |
| 68 | ||
| 69 | extern EthernetClient telnetClient; | |
| 70 | ||
| 71 | // Prototypes... | |
| 72 | byte telnetRead(EthernetClient client); | |
| 73 | byte telnetInput(EthernetClient client, char *cmdLine, byte len); | |
| 74 | #endif | |
| 75 | ||
| 76 | // And so it begins. | |
| 77 | void setup() | |
| 78 | {
| |
| 79 | Serial.begin(9600); | |
| 80 | ||
| 81 | while(!Serial); | |
| 82 | ||
| 83 | showHeader(); | |
| 84 | ||
| 85 | #if defined(ENET_PORT) | |
| 86 | telnetInit(); | |
| 87 | #endif | |
| 88 | ||
| 89 | showConfig(); | |
| 90 | ||
| 91 | // Scroll off any leftover console output. | |
| 92 | - | //for(int i=0; i<24; i++) print(); } // We don't really have anything loop worthy for this program, so we'll // just have some fun and pretend like we are starting up the CoCo each // time through. void loop() { showCoCoHeader(); // Just for fun... allram(); print(); print(F("BREAK IN 520")); print(F("OK")); delay(5000); } // Show program header. void showHeader() { // Emit some startup stuff to the serial port. print(F("\n" "*ALL RAM* BBS for Arduino "VERSION" - 30 year anniversary edition!\n" "Copyright (C) 1983 by Allen C. Huffman\n" "Ported from TRS-80 Color Computer Extended Color BASIC.\n" "Build Date: "__DATE__" "__TIME__"\n")); } /*---------------------------------------------------------------------------*/ // In BASIC, strings are dynamic. For C, we have to pre-allocate buffers for // the strings. #define INPUT_SIZE 32 // 64. For aStr, etc. #define MAX_USERS 3 // NM$(200) Userlog size. (0-200, 0 is Sysop) #define NAME_SIZE 12 // 20. Username size (nmStr) #define PSWD_SIZE 8 // 8. Password size (psStr & pwStr) #define ULOG_SIZE (NAME_SIZE+1+PSWD_SIZE+1+1) // To avoid hard coding some values, we define these here, too. Each message // is made up of lines, and the first line will contain the From, To, and // Subject separated by a character. So, while the original BASIC version // hard coded this, we will calculate it, letting the subject be as large // as whatever is left over (plus room for separaters and NULL at the end). #define FR_SIZE NAME_SIZE // From #define TO_SIZE NAME_SIZE // To #define SB_SIZE (INPUT_SIZE-FR_SIZE-1-TO_SIZE) // "From\To\Subj" // The original BASIC version was hard-coded to hold 20 messages of 11 lines // each (the first line was used for From/To/Subject). The Arduino has far // less RAM, so these have been made #defines so they can be changed. #define MAX_MSGS 3 // 19 (0-19, 20 messages) #define MAX_LINE 2 // 10 (0-10, 11 lines) // Rough estimate of how many bytes these items will take up. #define ULOG_MEM ((MAX_USERS+1)*(ULOG_SIZE)) #define MBASE_MEM ((MAX_MSGS+1)*MAX_LINE*INPUT_SIZE) // Validate the settings before compiling. #if (FR_SIZE+1+TO_SIZE+SB_SIZE > INPUT_SIZE)
|
| 92 | + | //for(int i=0; i<24; i++) print(); |
| 93 | } | |
| 94 | ||
| 95 | // We don't really have anything loop worthy for this program, so we'll | |
| 96 | // just have some fun and pretend like we are starting up the CoCo each | |
| 97 | // time through. | |
| 98 | void loop() | |
| 99 | {
| |
| 100 | showCoCoHeader(); // Just for fun... | |
| 101 | ||
| 102 | allram(); | |
| 103 | ||
| 104 | print(); | |
| 105 | print(F("BREAK IN 520"));
| |
| 106 | print(F("OK"));
| |
| 107 | ||
| 108 | delay(5000); | |
| 109 | } | |
| 110 | ||
| 111 | // Show program header. | |
| 112 | void showHeader() | |
| 113 | {
| |
| 114 | // Emit some startup stuff to the serial port. | |
| 115 | print(F("\n"
| |
| 116 | "*ALL RAM* BBS for Arduino "VERSION" - 30 year anniversary edition!\n" | |
| 117 | "Copyright (C) 1983 by Allen C. Huffman\n" | |
| 118 | "Ported from TRS-80 Color Computer Extended Color BASIC.\n" | |
| 119 | "Build Date: "__DATE__" "__TIME__"\n")); | |
| 120 | } | |
| 121 | ||
| 122 | /*---------------------------------------------------------------------------*/ | |
| 123 | // In BASIC, strings are dynamic. For C, we have to pre-allocate buffers for | |
| 124 | // the strings. | |
| 125 | #define INPUT_SIZE 32 // 64. For aStr, etc. | |
| 126 | ||
| 127 | #define MAX_USERS 3 // NM$(200) Userlog size. (0-200, 0 is Sysop) | |
| 128 | #define NAME_SIZE 12 // 20. Username size (nmStr) | |
| 129 | #define PSWD_SIZE 8 // 8. Password size (psStr & pwStr) | |
| 130 | #define ULOG_SIZE (NAME_SIZE+1+PSWD_SIZE+1+1) | |
| 131 | ||
| 132 | // To avoid hard coding some values, we define these here, too. Each message | |
| 133 | // is made up of lines, and the first line will contain the From, To, and | |
| 134 | // Subject separated by a character. So, while the original BASIC version | |
| 135 | // hard coded this, we will calculate it, letting the subject be as large | |
| 136 | // as whatever is left over (plus room for separaters and NULL at the end). | |
| 137 | #define FR_SIZE NAME_SIZE // From | |
| 138 | #define TO_SIZE NAME_SIZE // To | |
| 139 | #define SB_SIZE (INPUT_SIZE-FR_SIZE-1-TO_SIZE) // "From\To\Subj" | |
| 140 | ||
| 141 | - | cls(); // From line 5 |
| 141 | + | // The original BASIC version was hard-coded to hold 20 messages of 11 lines |
| 142 | // each (the first line was used for From/To/Subject). The Arduino has far | |
| 143 | // less RAM, so these have been made #defines so they can be changed. | |
| 144 | #define MAX_MSGS 3 // 19 (0-19, 20 messages) | |
| 145 | #define MAX_LINE 2 // 10 (0-10, 11 lines) | |
| 146 | ||
| 147 | // Rough estimate of how many bytes these items will take up. | |
| 148 | #define ULOG_MEM ((MAX_USERS+1)*(ULOG_SIZE)) | |
| 149 | #define MBASE_MEM ((MAX_MSGS+1)*MAX_LINE*INPUT_SIZE) | |
| 150 | ||
| 151 | // Validate the settings before compiling. | |
| 152 | #if (FR_SIZE+1+TO_SIZE+SB_SIZE > INPUT_SIZE) | |
| 153 | #error INPUT_SIZE too small to hold "From\To\Sub". | |
| 154 | #endif | |
| 155 | ||
| 156 | /*---------------------------------------------------------------------------*/ | |
| 157 | ||
| 158 | //0 REM *ALL RAM* BBS System 1.0 | |
| 159 | //1 REM Shareware / (C) 1983 | |
| 160 | //2 REM By Allen Huffman | |
| 161 | //3 REM 110 Champions Dr, #811 | |
| 162 | //4 REM Lufkin, TX 75901 | |
| 163 | //5 CLS:FORA=0TO8:READA$:POKE1024+A,VAL("&H"+A$):NEXTA:EXEC1024:DATAC6,1,96,BC,1F,2,7E,96,A3
| |
| 164 | //10 CLEAR21000:DIMNM$(200),MS$(19,10),A$,F$,S$,T$,BR$,CL$,NM$,PS$,PW$,A,B,C,CL,LN,LV,MS,NM,KY,UC | |
| 165 | ||
| 166 | // All variables in BASIC are global, so we are declaring them outside the | |
| 167 | // functions to make them global in C as well. Arrays in BASIC are "0 to X", | |
| 168 | // and in C they are "0 to X-1", so we add one to them in C to get the same | |
| 169 | // number of elements. | |
| 170 | char nmArray[MAX_USERS+1][ULOG_SIZE]; // NM$(200) | |
| 171 | char msArray[MAX_MSGS+1][MAX_LINE+1][INPUT_SIZE+1];// MS$(19,10) 1.4 | |
| 172 | char aStr[INPUT_SIZE+1]; // A$ 1.4 | |
| 173 | char fStr[FR_SIZE]; // F$ - From | |
| 174 | char sStr[SB_SIZE]; // S$ - Subj | |
| 175 | char tStr[TO_SIZE]; // T$ - To | |
| 176 | char nmStr[NAME_SIZE]; // NM$ - Name | |
| 177 | char psStr[PSWD_SIZE]; // PS$ - Pswd | |
| 178 | char pwStr[PSWD_SIZE]; // PW$ - Pswd | |
| 179 | ||
| 180 | // To save RAM, these two strings will exist in Flash memory. It will | |
| 181 | // require a bit of work later to use them (__FlashStringHelper*). | |
| 182 | prog_char brStr[] PROGMEM = "*==============*==============*"; // BR$ - border | |
| 183 | prog_char clStr[] PROGMEM = "\x0c\x0e"; // CL$ - clear | |
| 184 | ||
| 185 | int a, b, c, cl, ln, lv, ms, nm, ky, uc; | |
| 186 | // A, B, C - misc. | |
| 187 | // CL - Calls | |
| 188 | // LN - Line Number | |
| 189 | // LV - Level | |
| 190 | // MS - Messages | |
| 191 | // NM - Names (users) | |
| 192 | // KY - Keys (commands entered) | |
| 193 | // UC - Uppercase input (1=Yes, 0=No) | |
| 194 | ||
| 195 | void allram() | |
| 196 | - | nmStr[b-1] = '\0'; |
| 196 | + | |
| 197 | // HACK - create adefault Sysop account. | |
| 198 | nm = 0; | |
| 199 | strncpy_P(nmArray[0], PSTR("SYSOP\\TEST9"), ULOG_SIZE);
| |
| 200 | ||
| 201 | cls(); // From line 5 | |
| 202 | ||
| 203 | //15 CL$=CHR$(12)+CHR$(14):BR$="*==============*==============*":GOSUB555 | |
| 204 | //char cl[] = "\0xC\0xE"; | |
| 205 | //char br[] = "*==============*==============*"; | |
| 206 | gosub555(); | |
| 207 | ||
| 208 | //20 CLS:PRINTTAB(6)"*ALL RAM* BBS SYSTEM":PRINT"USERS:"NM,"CALLS:"CL:PRINTTAB(5)"SYSTEM AWAITING CALLER";:go:SOUND200,10 | |
| 209 | line20: | |
| 210 | nmStr[0] = 0; // reset user. | |
| 211 | cls(); | |
| 212 | printTab(6); | |
| 213 | print(F("*ALL RAM* BBS SYSTEM"));
| |
| 214 | - | if (ky<3) goto line30; goto line215; line45: //45 PRINT"*ACCEPTED*":PRINTBR$:PRINT"On-Line: "NM$:PRINT"Access :"LV:PRINT"Caller :"CL:KY=0:GOTO115 print(F("*ACCEPTED*")); print((__FlashStringHelper*)brStr); printSemi(F("On-Line: ")); print(nmStr); printSemi(F("Access :")); print(lv); printSemi(F("Caller :")); print(cl); ky = 0; goto line115; //50 'New User line55: //55 A$="Password Application Form":GOSUB1055 strncpy_P(aStr, PSTR("Password Application Form"), INPUT_SIZE); gosub1055(); //60 IFNM=200THENPRINT"Sorry, the userlog is full now.":GOTO215ELSEPRINT"Name=20 chars, Password=8 chars" if (nm==MAX_USERS) { print(F("Sorry, the userlog is full now.")); goto line215; } else { printSemi(F("Name=")); printNumSemi(NAME_SIZE); printSemi(F(" chars, Password=")); printNumSemi(PSWD_SIZE); printSemi(F(" chars")); } line65: //65 PRINT:PRINT"Full Name :";:UC=1:GOSUB1005:NM$=A$:IFA$=""ORLEN(A$)>20THEN30
|
| 214 | + | |
| 215 | printSemi(nm); | |
| 216 | printComma(); | |
| 217 | printSemi(F("CALLS:"));
| |
| 218 | print(cl); | |
| 219 | printTab(5); | |
| 220 | printSemi(F("SYSTEM AWAITING CALLER"));
| |
| 221 | //gosub1005(); | |
| 222 | if (gosub1005()==255) goto line20; | |
| 223 | sound(200,10); | |
| 224 | ||
| 225 | //25 A$="Welcome To *ALL RAM* BBS!":GOSUB1055:KY=0:CL=CL+1 | |
| 226 | strncpy_P(aStr, PSTR("Welcome To *ALL RAM* BBS!"), INPUT_SIZE);
| |
| 227 | gosub1055(); | |
| 228 | ky = 0; | |
| 229 | cl = cl + 1; | |
| 230 | ||
| 231 | showLoginMessage(); | |
| 232 | ||
| 233 | //30 PRINT:PRINT"Password or 'NEW' :";:UC=1:GOSUB1005:PS$=A$:IFA$=""ORA$="NEW"THEN55ELSEPRINT"Checking: ";:A=0 | |
| 234 | line30: | |
| 235 | print(); | |
| 236 | printSemi(F("Password or 'NEW' :"));
| |
| 237 | uc = 1; | |
| 238 | //gosub1005(); | |
| 239 | if (gosub1005()==255) goto line20; | |
| 240 | strncpy(psStr, aStr, PSWD_SIZE); | |
| 241 | if (aStr[0]=='\0' || strcmp(aStr, "NEW")==0) | |
| 242 | {
| |
| 243 | goto line55; | |
| 244 | } | |
| 245 | else | |
| 246 | {
| |
| 247 | printSemi(F("Checking: "));
| |
| 248 | a = 0; | |
| 249 | } | |
| 250 | ||
| 251 | line35: | |
| 252 | //35 A$=NM$(A):B=INSTR(A$,"\"):NM$=LEFT$(A$,B-1):PW$=MID$(A$,B+1,LEN(A$)-B-1):LV=VAL(RIGHT$(A$,1)):IFPW$=PS$THEN45ELSEA=A+1:IFA<=NM THEN35 | |
| 253 | strncpy(aStr, nmArray[a], ULOG_SIZE); | |
| 254 | b = instr(aStr, "\\"); | |
| 255 | strncpy(nmStr, aStr, b-1); | |
| 256 | nmStr[b-1] = '\0'; | |
| 257 | strncpy(pwStr, &aStr[b], strlen(aStr)-b-1); | |
| 258 | pwStr[strlen(aStr)-b-1] = '\0'; | |
| 259 | lv = atoi(&aStr[strlen(aStr)-1]); | |
| 260 | if (strncmp(pwStr, psStr, PSWD_SIZE)==0) | |
| 261 | {
| |
| 262 | goto line45; | |
| 263 | } | |
| 264 | else | |
| 265 | {
| |
| 266 | a = a + 1; | |
| 267 | if (a<=nm) goto line35; | |
| 268 | } | |
| 269 | ||
| 270 | line40: // for empty userlog bug | |
| 271 | //40 PRINT"*INVALID*":KY=KY+1:IFKY<3THEN30ELSE215 | |
| 272 | print(F("*INVALID*"));
| |
| 273 | ky = ky + 1; | |
| 274 | if (ky<3) goto line30; | |
| 275 | goto line215; | |
| 276 | ||
| 277 | line45: | |
| 278 | //45 PRINT"*ACCEPTED*":PRINTBR$:PRINT"On-Line: "NM$:PRINT"Access :"LV:PRINT"Caller :"CL:KY=0:GOTO115 | |
| 279 | print(F("*ACCEPTED*"));
| |
| 280 | print((__FlashStringHelper*)brStr); | |
| 281 | printSemi(F("On-Line: "));
| |
| 282 | print(nmStr); | |
| 283 | printSemi(F("Access :"));
| |
| 284 | print(lv); | |
| 285 | printSemi(F("Caller :"));
| |
| 286 | print(cl); | |
| 287 | ky = 0; | |
| 288 | goto line115; | |
| 289 | ||
| 290 | //50 'New User | |
| 291 | line55: | |
| 292 | //55 A$="Password Application Form":GOSUB1055 | |
| 293 | strncpy_P(aStr, PSTR("Password Application Form"), INPUT_SIZE);
| |
| 294 | gosub1055(); | |
| 295 | ||
| 296 | //60 IFNM=200THENPRINT"Sorry, the userlog is full now.":GOTO215ELSEPRINT"Name=20 chars, Password=8 chars" | |
| 297 | if (nm==MAX_USERS) | |
| 298 | {
| |
| 299 | print(F("Sorry, the userlog is full now."));
| |
| 300 | goto line215; | |
| 301 | } | |
| 302 | else | |
| 303 | {
| |
| 304 | printSemi(F("Name="));
| |
| 305 | printNumSemi(NAME_SIZE); | |
| 306 | printSemi(F(" chars, Password="));
| |
| 307 | printNumSemi(PSWD_SIZE); | |
| 308 | printSemi(F(" chars"));
| |
| 309 | } | |
| 310 | ||
| 311 | line65: | |
| 312 | //65 PRINT:PRINT"Full Name :";:UC=1:GOSUB1005:NM$=A$:IFA$=""ORLEN(A$)>20THEN30 | |
| 313 | print(); | |
| 314 | printSemi(F("Full Name :"));
| |
| 315 | uc = 1; | |
| 316 | //gosub1005(); | |
| 317 | if (gosub1005()==255) goto line20; | |
| 318 | strncpy(nmStr, aStr, NAME_SIZE); | |
| 319 | if (aStr[0]=='\0' || strlen(aStr)>20) goto line30; | |
| 320 | - | //135 IFLV5THENPRINT" Sorry, you are not validated.":GOTO125 |
| 320 | + | |
| 321 | - | if (lv5) |
| 321 | + | |
| 322 | printSemi(F("Password :"));
| |
| 323 | uc = 1; | |
| 324 | //gosub1005(); | |
| 325 | if (gosub1005()==255) goto line20; | |
| 326 | strncpy(pwStr, aStr, PSWD_SIZE); | |
| 327 | if (aStr[0]=='\0' || strlen(aStr)>8) goto line30; | |
| 328 | ||
| 329 | //75 PRINT:PRINT"Name :"NM$:PRINT"Pswd :"PW$:PRINT"Is this correct? ";:UC=1:GOSUB1005:IFLEFT$(A$,1)="Y"THEN80ELSE65 | |
| 330 | print(); | |
| 331 | printSemi(F("Name :"));
| |
| 332 | print(nmStr); | |
| 333 | printSemi(F("Pswd :"));
| |
| 334 | print(pwStr); | |
| 335 | printSemi(F("Is this correct? "));
| |
| 336 | uc = 1; | |
| 337 | //gosub1005(); | |
| 338 | if (gosub1005()==255) goto line20; | |
| 339 | if (aStr[0]=='Y') | |
| 340 | {
| |
| 341 | goto line80; | |
| 342 | } | |
| 343 | else | |
| 344 | {
| |
| 345 | goto line65; | |
| 346 | } | |
| 347 | ||
| 348 | line80: | |
| 349 | //80 NM=NM+1:NM$(NM)=NM$+"\"+PW$+"0":LV=0:KY=0 | |
| 350 | nm = nm + 1; | |
| 351 | strncpy(nmArray[nm], nmStr, NAME_SIZE); | |
| 352 | strcat_P(nmArray[nm], PSTR("\\"));
| |
| 353 | strncat(nmArray[nm], pwStr, PSWD_SIZE); | |
| 354 | //strcat_P(nmArray[nm], PSTR("0"));
| |
| 355 | strcat_P(nmArray[nm], PSTR("1")); // AUTO VALIDATED
| |
| 356 | //lv = 0; | |
| 357 | lv = 1; | |
| 358 | ky = 0; | |
| 359 | //85 PRINT"Your password will be validated as soon as time permits. Press":PRINT"[ENTER] to continue :";:GOSUB1005 | |
| 360 | print(F("Your password will be validated as soon as time permits. Press"));
| |
| 361 | printSemi(F("[ENTER] to continue :"));
| |
| 362 | //gosub1005(); | |
| 363 | if (gosub1005()==255) goto line20; | |
| 364 | ||
| 365 | //100 'Main Menu | |
| 366 | line105: | |
| 367 | //105 A$="*ALL RAM* BBS Master Menu":GOSUB1055 | |
| 368 | strncpy_P(aStr, PSTR("*ALL RAM* BBS Master Menu"), INPUT_SIZE);
| |
| 369 | gosub1055(); | |
| 370 | ||
| 371 | //110 PRINT"C-all Sysop","P-ost Msg":PRINT"G-oodbye","R-ead Msg":PRINT"U-serlog","S-can Titles" | |
| 372 | printSemi(F("C-all Sysop"));
| |
| 373 | printComma(); | |
| 374 | print(F("P-ost Msg"));
| |
| 375 | printSemi(F("G-oodbye"));
| |
| 376 | printComma(); | |
| 377 | print(F("R-ead Msg"));
| |
| 378 | printSemi(F("U-serlog"));
| |
| 379 | printComma(); | |
| 380 | print(F("S-can Titles"));
| |
| 381 | ||
| 382 | line115: | |
| 383 | //115 PRINTBR$ | |
| 384 | print((__FlashStringHelper*)brStr); | |
| 385 | ||
| 386 | line120: | |
| 387 | //120 KY=KY+1:IFKY>200THENPRINT"Sorry, your time on-line is up.":GOTO210ELSEIFKY>180THENPRINT"Please complete your call soon." | |
| 388 | ky = ky + 1; | |
| 389 | if (ky>200) | |
| 390 | {
| |
| 391 | print(F("Sorry, your time on-line is up."));
| |
| 392 | goto line210; | |
| 393 | } | |
| 394 | else if (ky>180) | |
| 395 | {
| |
| 396 | print(F("Please complete your call soon."));
| |
| 397 | } | |
| 398 | ||
| 399 | line125: | |
| 400 | showFreeRam(); | |
| 401 | //125 PRINTTAB(7)"?=Menu/Command :";:UC=1:GOSUB1005:A$=LEFT$(A$,1) | |
| 402 | printTab(7); | |
| 403 | printSemi(F("?=Menu/Command :"));
| |
| 404 | uc = 1; | |
| 405 | //gosub1005(); | |
| 406 | if (gosub1005()==255) goto line20; | |
| 407 | aStr[1] = '\0'; | |
| 408 | ||
| 409 | line130: | |
| 410 | //130 LN=INSTR("?CGRSPU%",A$):IFLN=0THENPRINT"*Invalid Command*":GOTO120
| |
| 411 | ln = instr("?CGRSPU%", aStr);
| |
| 412 | if (ln==0) | |
| 413 | {
| |
| 414 | print(F("*Invalid Command*"));
| |
| 415 | goto line120; | |
| 416 | } | |
| 417 | ||
| 418 | //135 IFLV<1ANDLN>5THENPRINT" Sorry, you are not validated.":GOTO125 | |
| 419 | if (lv<1 && ln>5) | |
| 420 | {
| |
| 421 | print(F(" Sorry, you are not validated."));
| |
| 422 | goto line125; | |
| 423 | } | |
| 424 | ||
| 425 | //140 ONLN GOTO105,155,205,405,455,305,255,505 | |
| 426 | if (ln==1) goto line105; | |
| 427 | if (ln==2) goto line155; | |
| 428 | if (ln==3) goto line205; | |
| 429 | if (ln==4) goto line405; | |
| 430 | if (ln==5) goto line455; | |
| 431 | if (ln==6) goto line305; | |
| 432 | if (ln==7) goto line255; | |
| 433 | if (ln==8) goto line505; | |
| 434 | ||
| 435 | //150 'Call Sysop | |
| 436 | line155: | |
| 437 | //155 A$="Calling the Sysop":GOSUB1055:A=0 | |
| 438 | strncpy_P(aStr, PSTR("Calling the Sysop"), INPUT_SIZE);
| |
| 439 | gosub1055(); | |
| 440 | a = 0; | |
| 441 | ||
| 442 | //165 PRINT" BEEP!";:SOUND150,5:IFINKEY$=CHR$(12)THEN175ELSEprintING$(5,8);:A=A+1:IFA<25THEN165 | |
| 443 | line165: | |
| 444 | printSemi(F(" BEEP!"));
| |
| 445 | sound(150, 5); | |
| 446 | if (inkey()==12) | |
| 447 | {
| |
| 448 | goto line175; | |
| 449 | } | |
| 450 | else | |
| 451 | {
| |
| 452 | string(5, 8); | |
| 453 | a = a + 1; | |
| 454 | if (a<25) goto line165; | |
| 455 | } | |
| 456 | ||
| 457 | //170 PRINT:PRINT" The Sysop is unavaliable now.":GOTO115 | |
| 458 | print(F(""));
| |
| 459 | print(F(" The Sysop is unavaliable now."));
| |
| 460 | goto line115; | |
| 461 | ||
| 462 | line175: | |
| 463 | //175 PRINT:PRINTTAB(6)"*Chat mode engaged*" | |
| 464 | print(); | |
| 465 | printTab(6); | |
| 466 | print(F("*Chat mode engaged*"));
| |
| 467 | ||
| 468 | line180: | |
| 469 | //180 GOSUB1005:IFLEFT$(A$,3)="BYE"THEN185ELSE180 | |
| 470 | //gosub1005(); | |
| 471 | if (gosub1005()==255) goto line20; | |
| 472 | if (strncmp(aStr, "BYE", 3)==0) | |
| 473 | {
| |
| 474 | goto line185; | |
| 475 | } | |
| 476 | else | |
| 477 | {
| |
| 478 | goto line180; | |
| 479 | } | |
| 480 | ||
| 481 | line185: | |
| 482 | //185 PRINTTAB(5)"*Chat mode terminated*":GOTO115 | |
| 483 | goto line115; | |
| 484 | - | for (a=0; a<=MAX_LINE; a++) { msArray[ms][a][0] = '\0'; } strncpy(fStr, nmStr, NAME_SIZE); //315 PRINT"From :"F$:PRINT"To :";:UC=1:GOSUB1005:A$=LEFT$(A$,20):T$=A$:IFA$=""THEN115 printSemi(F("From :")); print(fStr); printSemi(F("To :")); uc = 1; //gosub1005(); if (gosub1005()==255) goto line20; aStr[NAME_SIZE] = '\0'; strncpy(tStr, aStr, TO_SIZE); if (aStr[0]=='\0') goto line115; //320 PRINT"Is this message private? ";:UC=1:GOSUB1005:IFLEFT$(A$,1)="Y"THENS$="*E-Mail*":GOTO330 printSemi(F("Is this message private? ")); uc = 1; //gosub1005(); if (gosub1005()==255) goto line20; if (aStr[0]=='Y') { strncpy_P(sStr, PSTR("*E-Mail*"), SB_SIZE); goto line330; } //325 PRINT"Subj :";:UC=1:GOSUB1005:A$=LEFT$(A$,18):S$=A$:IFA$=""THEN115 printSemi(F("Subj :")); uc = 1; //gosub1005(); if (gosub1005()==255) goto line20; aStr[SB_SIZE-1] = '\0'; strncpy(sStr, aStr, SB_SIZE); if (aStr[0]=='\0') goto line115; line330: //330 PRINT"Enter up to 10 lines, 64 chars. [ENTER] on a blank line to end.":A=0 printSemi(F("Enter up to")); printSemi(MAX_LINE); printSemi(F("lines,")); printSemi(INPUT_SIZE); print(F("chars. [ENTER] on a blank line to end.")); a = 0; line335: //335 A=A+1:PRINTUSING"##>";A;:GOSUB1005:MS$(MS,A)=A$:IFA$=""THENA=A-1:GOTO345ELSEIFA", a);
|
| 484 | + | |
| 485 | //200 'Goodbye | |
| 486 | line205: | |
| 487 | //205 A$="Thank you for calling":GOSUB1055 | |
| 488 | strncpy_P(aStr, PSTR("Thank you for calling"), INPUT_SIZE);
| |
| 489 | gosub1055(); | |
| 490 | ||
| 491 | line210: | |
| 492 | //210 PRINT:PRINT"Goodbye, "NM$"!":PRINT:PRINT"Please call again." | |
| 493 | print(F(""));
| |
| 494 | printSemi(F("Goodbye, "));
| |
| 495 | printSemi(nmStr); | |
| 496 | print(F("!"));
| |
| 497 | print(); | |
| 498 | print(F("Please call again."));
| |
| 499 | ||
| 500 | line215: | |
| 501 | //215 PRINT:PRINT:PRINT"*ALL RAM* BBS disconnecting..." | |
| 502 | print(); | |
| 503 | print(); | |
| 504 | print(F("*ALL RAM* BBS disconnecting..."));
| |
| 505 | ||
| 506 | //220 FORA=1TO1000:NEXTA | |
| 507 | delay(1000); | |
| 508 | ||
| 509 | #if defined(ENET_PORT) | |
| 510 | telnetDisconnect(); | |
| 511 | #endif | |
| 512 | ||
| 513 | //225 GOTO20 | |
| 514 | goto line20; | |
| 515 | ||
| 516 | //250 'Userlog | |
| 517 | line255: | |
| 518 | //255 A$="List of Users":GOSUB1055:PRINT"Users on system:"NM:IFNM=0THEN115ELSEA=1 | |
| 519 | strncpy_P(aStr, PSTR("List of Users"), INPUT_SIZE);
| |
| 520 | gosub1055(); | |
| 521 | printSemi(F("Users on system:"));
| |
| 522 | print(nm); | |
| 523 | if (nm==0) | |
| 524 | {
| |
| 525 | goto line115; | |
| 526 | - | line360: |
| 526 | + | |
| 527 | - | //360 PRINT"Edit line 1 -"A":";:GOSUB1005:LN=VAL(LEFT$(A$,2)):IFLNA THEN345 |
| 527 | + | |
| 528 | {
| |
| 529 | a = 1; | |
| 530 | } | |
| 531 | line260: | |
| 532 | //260 A$=NM$(A):PRINTLEFT$(A$,INSTR(A$,"\")-1)TAB(29)RIGHT$(A$,1) | |
| 533 | strncpy(aStr, nmArray[a], INPUT_SIZE); | |
| 534 | {
| |
| 535 | - | if (lna) goto line345; |
| 535 | + | |
| 536 | strncpy(tempStr, aStr, NAME_SIZE+1); | |
| 537 | tempStr[instr(tempStr, "\\")-1] = '\0'; | |
| 538 | printSemi(tempStr); | |
| 539 | } | |
| 540 | printTab(29); | |
| 541 | print(right(aStr,1)); | |
| 542 | ||
| 543 | //265 IF(A/10)=INT(A/10)THENPRINT"C-ontinue or S-top :";:UC=1:GOSUB1005:IFLEFT$(A$,1)="S"THEN275 | |
| 544 | if (a % 10 == 9) | |
| 545 | {
| |
| 546 | printSemi(F("C-ontinue or S-top :"));
| |
| 547 | uc = 1; | |
| 548 | //gosub1005(); | |
| 549 | if (gosub1005()==255) goto line20; | |
| 550 | if (aStr[0]=='S') goto line275; | |
| 551 | } | |
| 552 | ||
| 553 | //270 A=A+1:IFA<=NM THEN260 | |
| 554 | a = a + 1; | |
| 555 | if (a<=nm) goto line260; | |
| 556 | ||
| 557 | line275: | |
| 558 | //275 PRINT"*End of Userlog*":GOTO115 | |
| 559 | print(F("*End of Userlog*"));
| |
| 560 | goto line115; | |
| 561 | ||
| 562 | - | for (b=1; b<=a; b++) { printUsingSemi("##>", b);
|
| 562 | + | |
| 563 | line305: | |
| 564 | //305 IFMS=20THENPRINT"One moment, making room...":FORA=0TO18:FORB=0TO10:MS$(A,B)=MS$(A+1,B):NEXTB:NEXTA:MS=19 | |
| 565 | if (ms==MAX_MSGS+1) | |
| 566 | {
| |
| 567 | print(F("One moment, making room..."));
| |
| 568 | for(a=0; a<=MAX_MSGS-1; a++) | |
| 569 | {
| |
| 570 | for(b=0; b<=MAX_LINE; b++) | |
| 571 | {
| |
| 572 | strncpy(msArray[a][b], msArray[a+1][b], INPUT_SIZE); | |
| 573 | } | |
| 574 | } | |
| 575 | ms = MAX_MSGS; | |
| 576 | } | |
| 577 | //310 CLS:PRINTCL$"This will be message #"MS+1:FORA=0TO10:MS$(MS,A)="":NEXTA:F$=NM$ | |
| 578 | cls(); | |
| 579 | print((__FlashStringHelper*)clStr); | |
| 580 | printSemi(F("This will be message #"));
| |
| 581 | print(ms+1); | |
| 582 | for (a=0; a<=MAX_LINE; a++) | |
| 583 | {
| |
| 584 | msArray[ms][a][0] = '\0'; | |
| 585 | } | |
| 586 | strncpy(fStr, nmStr, NAME_SIZE); | |
| 587 | ||
| 588 | //315 PRINT"From :"F$:PRINT"To :";:UC=1:GOSUB1005:A$=LEFT$(A$,20):T$=A$:IFA$=""THEN115 | |
| 589 | printSemi(F("From :"));
| |
| 590 | print(fStr); | |
| 591 | printSemi(F("To :"));
| |
| 592 | uc = 1; | |
| 593 | //gosub1005(); | |
| 594 | if (gosub1005()==255) goto line20; | |
| 595 | aStr[NAME_SIZE] = '\0'; | |
| 596 | strncpy(tStr, aStr, TO_SIZE); | |
| 597 | if (aStr[0]=='\0') goto line115; | |
| 598 | ||
| 599 | - | //415 PRINT"Read Message 1 -"MS":";:GOSUB1005:A=VAL(LEFT$(A$,2)):IFAMS THEN115 |
| 599 | + | //320 PRINT"Is this message private? ";:UC=1:GOSUB1005:IFLEFT$(A$,1)="Y"THENS$="*E-Mail*":GOTO330 |
| 600 | printSemi(F("Is this message private? "));
| |
| 601 | uc = 1; | |
| 602 | //gosub1005(); | |
| 603 | if (gosub1005()==255) goto line20; | |
| 604 | if (aStr[0]=='Y') | |
| 605 | {
| |
| 606 | strncpy_P(sStr, PSTR("*E-Mail*"), SB_SIZE);
| |
| 607 | - | if (ams) goto line115; |
| 607 | + | goto line330; |
| 608 | } | |
| 609 | ||
| 610 | //325 PRINT"Subj :";:UC=1:GOSUB1005:A$=LEFT$(A$,18):S$=A$:IFA$=""THEN115 | |
| 611 | printSemi(F("Subj :"));
| |
| 612 | uc = 1; | |
| 613 | //gosub1005(); | |
| 614 | if (gosub1005()==255) goto line20; | |
| 615 | aStr[SB_SIZE-1] = '\0'; | |
| 616 | - | fStr[ c-b-1] = '\0'; // FIXTHIS - max copy sizes here? |
| 616 | + | strncpy(sStr, aStr, SB_SIZE); |
| 617 | if (aStr[0]=='\0') goto line115; | |
| 618 | ||
| 619 | line330: | |
| 620 | //330 PRINT"Enter up to 10 lines, 64 chars. [ENTER] on a blank line to end.":A=0 | |
| 621 | printSemi(F("Enter up to"));
| |
| 622 | printSemi(MAX_LINE); | |
| 623 | printSemi(F("lines,"));
| |
| 624 | printSemi(INPUT_SIZE); | |
| 625 | print(F("chars. [ENTER] on a blank line to end."));
| |
| 626 | a = 0; | |
| 627 | ||
| 628 | line335: | |
| 629 | //335 A=A+1:PRINTUSING"##>";A;:GOSUB1005:MS$(MS,A)=A$:IFA$=""THENA=A-1:GOTO345ELSEIFA<10THEN335 | |
| 630 | a = a + 1; | |
| 631 | printUsingSemi("##>", a);
| |
| 632 | //gosub1005(); | |
| 633 | if (gosub1005()==255) goto line20; | |
| 634 | strncpy(msArray[ms][a], aStr, INPUT_SIZE); | |
| 635 | if (aStr[0]=='\0') | |
| 636 | {
| |
| 637 | a = a - 1; | |
| 638 | goto line345; | |
| 639 | } | |
| 640 | else if (a<MAX_LINE) goto line335; | |
| 641 | ||
| 642 | line340: | |
| 643 | //340 PRINT"*Message Buffer Full*" | |
| 644 | print(F("*Message Buffer Full*"));
| |
| 645 | ||
| 646 | line345: | |
| 647 | //345 PRINT"A-bort, C-ont, E-dit, L-ist, or S-ave Message? ";:UC=1:GOSUB1005:A$=LEFT$(A$,1):IFA$=""THEN345 | |
| 648 | printSemi(F("A-bort, C-ont, E-dit, L-ist, or S-ave Message? "));
| |
| 649 | uc = 1; | |
| 650 | //gosub1005(); | |
| 651 | if (gosub1005()==255) goto line20; | |
| 652 | aStr[1] = '\0'; | |
| 653 | if (aStr[0]=='\0') goto line345; | |
| 654 | ||
| 655 | //350 LN=INSTR("ACELS",A$):IFLN=0THEN345ELSEONLN GOTO385,355,360,375,380
| |
| 656 | ln = instr("ACELS", aStr);
| |
| 657 | if (ln==0) goto line345; | |
| 658 | if (ln==1) goto line385; | |
| 659 | if (ln==2) goto line355; | |
| 660 | if (ln==3) goto line360; | |
| 661 | if (ln==4) goto line375; | |
| 662 | if (ln==5) goto line380; | |
| 663 | ||
| 664 | line355: | |
| 665 | //355 IFA<10THENPRINT"Continue your message:":GOTO335ELSE340 | |
| 666 | if (a<MAX_LINE) | |
| 667 | {
| |
| 668 | printSemi(F("Continue your message:"));
| |
| 669 | goto line335; | |
| 670 | } | |
| 671 | else goto line340; | |
| 672 | ||
| 673 | line360: | |
| 674 | - | //465 A$=MS$(A,0):PRINTUSING"[##] SB: ";A+1;:B=INSTR(A$,"\"):C=INSTR(B+1,A$,"\"):PRINTRIGHT$(A$,LEN(A$)-C):PRINTTAB(5)"TO: "LEFT$(A$,B-1):A=A+1:IFA strncpy(aStr, msArray[a][0], INPUT_SIZE); |
| 674 | + | //360 PRINT"Edit line 1 -"A":";:GOSUB1005:LN=VAL(LEFT$(A$,2)):IFLN<1ORLN>A THEN345 |
| 675 | printSemi(F("Edit line 1 -"));
| |
| 676 | printSemi(a); | |
| 677 | printSemi(F(":"));
| |
| 678 | //gosub1005(); | |
| 679 | if (gosub1005()==255) goto line20; | |
| 680 | aStr[2] = '\0'; | |
| 681 | ln = atoi(aStr); | |
| 682 | if (ln<1 || ln>a) goto line345; | |
| 683 | ||
| 684 | //365 PRINT"Line currently reads:":PRINTMS$(MS,LN):PRINT"Enter new line:":GOSUB1005:A$=LEFT$(A$,64):IFA$=""THENPRINT"*Unchanged*"ELSEMS$(MS,LN)=A$:PRINT"*Corrected*" | |
| 685 | print(F("Line currently reads:"));
| |
| 686 | print(msArray[ms][ln]); | |
| 687 | print(F("Enter new line:"));
| |
| 688 | //gosub1005(); | |
| 689 | if (gosub1005()==255) goto line20; | |
| 690 | aStr[INPUT_SIZE] = '\0'; // 1.4 | |
| 691 | if (aStr[0]=='\0') | |
| 692 | {
| |
| 693 | print(F("*Unchanged*"));
| |
| 694 | } | |
| 695 | else | |
| 696 | {
| |
| 697 | strncpy(msArray[ms][ln], aStr, INPUT_SIZE); | |
| 698 | print(F("*Corrected*"));
| |
| 699 | } | |
| 700 | ||
| 701 | //370 GOTO360 | |
| 702 | goto line360; | |
| 703 | ||
| 704 | line375: | |
| 705 | //375 CLS:PRINTCL$"Message Reads:":FORB=1TOA:PRINTUSING"##>";B;:PRINTMS$(MS,B):NEXTB:GOTO345 | |
| 706 | cls(); | |
| 707 | print((__FlashStringHelper*)clStr); | |
| 708 | print(F("Message Reads:"));
| |
| 709 | for (b=1; b<=a; b++) | |
| 710 | {
| |
| 711 | printUsingSemi("##>", b);
| |
| 712 | print(msArray[ms][b]); | |
| 713 | } | |
| 714 | goto line345; | |
| 715 | ||
| 716 | line380: | |
| 717 | //380 MS$(MS,0)=T$+"\"+F$+"\"+S$:MS=MS+1:PRINT"*Message"MS"stored*":GOTO115 | |
| 718 | strcpy(msArray[ms][0], tStr); | |
| 719 | strcat_P(msArray[ms][0], PSTR("\\"));
| |
| 720 | strcat(msArray[ms][0], fStr); | |
| 721 | strcat_P(msArray[ms][0], PSTR("\\"));
| |
| 722 | strcat(msArray[ms][0], sStr); | |
| 723 | ms = ms + 1; | |
| 724 | printSemi(F("*Message"));
| |
| 725 | printSemi(ms); | |
| 726 | print(F("stored*"));
| |
| 727 | goto line115; | |
| 728 | ||
| 729 | line385: | |
| 730 | //385 PRINT"*Message Aborted*":GOTO115 | |
| 731 | print(F("*Message Aborted*"));
| |
| 732 | goto line115; | |
| 733 | ||
| 734 | //400 'Read Msg | |
| 735 | line405: | |
| 736 | //405 IFMS=0THENPRINT"The message base is empty.":GOTO115 | |
| 737 | if (ms==0) | |
| 738 | {
| |
| 739 | print(F("The message base is empty."));
| |
| 740 | goto line115; | |
| 741 | } | |
| 742 | ||
| 743 | //410 CLS:PRINTCL$ | |
| 744 | cls(); | |
| 745 | print((__FlashStringHelper*)clStr); | |
| 746 | ||
| 747 | line415: | |
| 748 | //415 PRINT"Read Message 1 -"MS":";:GOSUB1005:A=VAL(LEFT$(A$,2)):IFA<1ORA>MS THEN115 | |
| 749 | printSemi(F("Read Message 1 -"));
| |
| 750 | printSemi(ms); | |
| 751 | printSemi(F(":"));
| |
| 752 | //gosub1005(); | |
| 753 | if (gosub1005()==255) goto line20; | |
| 754 | aStr[2] = '\0'; | |
| 755 | a = atoi(aStr); | |
| 756 | if (a<1 || a>ms) goto line115; | |
| 757 | ||
| 758 | //420 A$=MS$(A-1,0):B=INSTR(A$,"\"):C=INSTR(B+1,A$,"\"):T$=LEFT$(A$,B-1):F$=MID$(A$,B+1,C-B-1):S$=RIGHT$(A$,LEN(A$)-C) | |
| 759 | strncpy(aStr, msArray[a-1][0], INPUT_SIZE); | |
| 760 | b = instr(aStr, "\\"); | |
| 761 | c = instr(b+1, aStr, "\\"); | |
| 762 | strncpy(tStr, aStr, b-1); | |
| 763 | tStr[b-1] = '\0'; | |
| 764 | strncpy(fStr, (aStr-1)+b+1, c-b-1); | |
| 765 | fStr[c-b-1] = '\0'; // FIXTHIS - max copy sizes here? | |
| 766 | strncpy(sStr, right(aStr, strlen(aStr)-c), SB_SIZE); | |
| 767 | ||
| 768 | //425 IFS$="*E-Mail*"ANDLV<8THENIFNM$<>T$ANDNM$<>F$THENPRINT"That message is private.":GOTO415 | |
| 769 | if (strcmp(sStr, "*E-Mail*")==0 && lv<8) | |
| 770 | {
| |
| 771 | if (strcmp(nmStr, tStr)!=0 && strcmp(nmStr, fStr)!=0) | |
| 772 | - | for (c=0; c<strlen(aStr); c++) { ch = aStr[ c]; if (ch>96) aStr[ c] = ch-32;
|
| 772 | + | |
| 773 | print(F("That message is private."));
| |
| 774 | - | if (ch==92) aStr[ c] = '/'; |
| 774 | + | |
| 775 | } | |
| 776 | } | |
| 777 | ||
| 778 | //430 CLS:PRINTCL$"Message #"A:PRINT"From :"F$:PRINT"To :"T$:PRINT"Subj :"S$:PRINT:B=0 | |
| 779 | cls(); | |
| 780 | print((__FlashStringHelper*)clStr); | |
| 781 | printSemi(F("Message #"));
| |
| 782 | print(a); | |
| 783 | printSemi(F("From :"));
| |
| 784 | print(fStr); | |
| 785 | printSemi(F("To :"));
| |
| 786 | print(tStr); | |
| 787 | printSemi(F("Subj :"));
| |
| 788 | print(sStr); | |
| 789 | print(); | |
| 790 | b = 0; | |
| 791 | ||
| 792 | line435: | |
| 793 | //435 B=B+1:PRINTMS$(A-1,B):IFMS$(A-1,B)=""THEN440ELSEIFB<10THEN435 | |
| 794 | b = b + 1; | |
| 795 | print(msArray[a-1][b]); | |
| 796 | if (msArray[a-1][b][0]=='\0') | |
| 797 | {
| |
| 798 | goto line440; | |
| 799 | } | |
| 800 | else if (b<MAX_LINE) goto line435; | |
| 801 | ||
| 802 | line440: | |
| 803 | //440 PRINT"*End of Message*":GOTO415 | |
| 804 | print(F("*End of Message*"));
| |
| 805 | goto line415; | |
| 806 | ||
| 807 | //450 'Scan Titles | |
| 808 | line455: | |
| 809 | //455 IFMS=0THENPRINT"The message base is empty.":GOTO115 | |
| 810 | if (ms==0) | |
| 811 | {
| |
| 812 | print(F("The message base is empty."));
| |
| 813 | goto line115; | |
| 814 | } | |
| 815 | ||
| 816 | //460 CLS:PRINTCL$"Message Titles:":A=0 | |
| 817 | cls(); | |
| 818 | print((__FlashStringHelper*)clStr); | |
| 819 | print(F("Message Titles:"));
| |
| 820 | a = 0; | |
| 821 | ||
| 822 | line465: | |
| 823 | //465 A$=MS$(A,0):PRINTUSING"[##] SB: ";A+1;:B=INSTR(A$,"\"):C=INSTR(B+1,A$,"\"):PRINTRIGHT$(A$,LEN(A$)-C):PRINTTAB(5)"TO: "LEFT$(A$,B-1):A=A+1:IFA<MS THEN465 | |
| 824 | strncpy(aStr, msArray[a][0], INPUT_SIZE); | |
| 825 | printUsingSemi("[##] SB: ", a+1);
| |
| 826 | b = instr(aStr, "\\"); | |
| 827 | c = instr(b+1, aStr, "\\"); | |
| 828 | print(right(aStr, strlen(aStr)-c)); | |
| 829 | printTab(5); | |
| 830 | printSemi(F("TO: "));
| |
| 831 | {
| |
| 832 | char tempStr[TO_SIZE]; | |
| 833 | strncpy(tempStr, aStr, b-1); | |
| 834 | tempStr[b-1] = '\0'; | |
| 835 | print(tempStr); | |
| 836 | } | |
| 837 | - | if (pos<1) return 0; return instr(aStr+pos, substr) + pos; } int instr(char *str, char *substr) { char *ptr; ptr = strstr(str, substr); if (ptr==NULL) return 0; // No match? if (ptr==&str[strlen(str)]) return 0; // Matched the \0 at end of line? return ptr-str+1; } /*---------------------------------------------------------------------------*/ // Input functions. #ifdef ENET_PORT byte lineinput(char *cmdLine, byte len) { return telnetInput(telnetClient, cmdLine, len); } #else // LINE INPUT str // Read string up to len bytes. This code comes from my Hayes AT Command // parser, so the variables are named differently. #define CR 13 #define BEL 7 #define BS 8 #define CAN 24 byte lineinput(char *cmdLine, byte len) { int ch; byte cmdLen = 0; boolean done; done = false; while(!done) { //ledBlink(); ch = -1; // -1 is no data available if (Serial.available()>0)
|
| 837 | + | |
| 838 | if (a<ms) goto line465; | |
| 839 | ||
| 840 | //470 PRINT"*End of Messages*":GOTO115 | |
| 841 | print(F("*End of Messages*"));
| |
| 842 | goto line115; | |
| 843 | ||
| 844 | //500 '%SYSOP MENU% | |
| 845 | line505: | |
| 846 | //505 IFLV<9THENA$="Z":GOTO130 | |
| 847 | if (lv<9) | |
| 848 | {
| |
| 849 | strncpy_P(aStr, PSTR("Z"), INPUT_SIZE);
| |
| 850 | goto line130; | |
| 851 | } | |
| 852 | ||
| 853 | //510 PRINT"PASSWORD?";:GOSUB1005:IFA$<>"?DROWSSAP"THENPRINT"Thank You!":GOTO115 | |
| 854 | printSemi(F("PASSWORD?"));
| |
| 855 | //gosub1005(); | |
| 856 | if (gosub1005()==255) goto line20; | |
| 857 | if (strcmp(aStr, "?DROWSSAP")!=0) | |
| 858 | {
| |
| 859 | print(F("Thank You!"));
| |
| 860 | goto line115; | |
| 861 | } | |
| 862 | ||
| 863 | //515 PRINT"Abort BBS? YES or NO? ";:UC=1:GOSUB1005:IFA$<>"YES"THEN115 | |
| 864 | printSemi(F("Abort BBS? YES or NO? "));
| |
| 865 | uc = 1; | |
| 866 | //gosub1005(); | |
| 867 | if (gosub1005()==255) goto line20; | |
| 868 | if (strcmp(aStr, "YES")!=0) goto line115; | |
| 869 | ||
| 870 | //520 GOSUB605:STOP | |
| 871 | gosub605(); | |
| 872 | return; | |
| 873 | - | if (cmdLen<len) { if ((ch>31) && (ch<127)) // isprint(ch) does not work.
|
| 873 | + | |
| 874 | ||
| 875 | /*---------------------------------------------------------------------------*/ | |
| 876 | // Subroutines (formerly GOSUBs) | |
| 877 | // | |
| 878 | //550 '%LOAD% | |
| 879 | void gosub555() | |
| 880 | {
| |
| 881 | //555 PRINT"%LOAD% [ENTER] WHEN READY";:GOSUB1005 | |
| 882 | printSemi(F("%LOAD% [ENTER] WHEN READY"));
| |
| 883 | //gosub1005(); | |
| 884 | print(); | |
| 885 | if (aStr[0]=='!') return; | |
| 886 | ||
| 887 | //560 OPEN"I",#-1,"USERLOG":INPUT#-1,CL,NM:FORA=0TONM:INPUT#-1,NM$(A):NEXTA:CLOSE | |
| 888 | loadUserlog(); | |
| 889 | ||
| 890 | //565 OPEN"I",#-1,"MSG BASE":INPUT#-1,MS:FORA=0TOMS-1:FORB=0TO10:INPUT#-1,MS$(A,B):NEXTB:NEXTA:CLOSE:RETURN | |
| 891 | loadMsgBase(); | |
| 892 | } | |
| 893 | ||
| 894 | //600 '%SAVE% | |
| 895 | void gosub605() | |
| 896 | {
| |
| 897 | //605 PRINT"%SAVE% [ENTER] WHEN READY";:GOSUB1005:MOTORON:FORA=0TO999:NEXTA | |
| 898 | printSemi(F("%SAVE% [ENTER] WHEN READY"));
| |
| 899 | gosub1005(); | |
| 900 | ||
| 901 | //610 OPEN"O",#-1,"USERLOG":PRINT#-1,CL,NM:FORA=0TONM:PRINT#-1,NM$(A):NEXTA:CLOSE | |
| 902 | saveUserlog(); | |
| 903 | ||
| 904 | //615 OPEN"O",#-1,"MSG BASE":PRINT#-1,MS:FORA=0TOMS-1:FORB=0TO10:PRINT#-1,MS$(A,B):NEXTB:NEXTA:CLOSE:RETURN | |
| 905 | saveMsgBase(); | |
| 906 | } | |
| 907 | ||
| 908 | //1000 'User Input | |
| 909 | #define CR 13 | |
| 910 | #define INBUF_SIZE 64 | |
| 911 | byte gosub1005() | |
| 912 | {
| |
| 913 | byte ch; // Used only here, so we can make it local. | |
| 914 | byte count; | |
| 915 | ||
| 916 | //1005 LINEINPUTA$:A$=LEFT$(A$,64):IFUC=0ORA$=""THENRETURN | |
| 917 | count = lineinput(aStr, INPUT_SIZE); | |
| 918 | aStr[INPUT_SIZE] = '\0'; | |
| 919 | if ((uc==0) || (aStr[0]=='\0')) return count; | |
| 920 | ||
| 921 | //1010 FORC=1TOLEN(A$):CH=ASC(MID$(A$,C,1)):IFCH>96THENMID$(A$,C,1)=CHR$(CH-32) | |
| 922 | for (c=0; c<strlen(aStr); c++) | |
| 923 | {
| |
| 924 | ch = aStr[1]; | |
| 925 | if (ch>96) aStr[1] = ch-32; | |
| 926 | //1015 IFCH=92THENMID$(A$,C,1)="/" | |
| 927 | if (ch==92) aStr[1] = '/'; | |
| 928 | //1020 NEXTC:UC=0:RETURN | |
| 929 | } | |
| 930 | uc = 0; | |
| 931 | ||
| 932 | return count; | |
| 933 | } | |
| 934 | ||
| 935 | //1050 'Function Border | |
| 936 | void gosub1055() | |
| 937 | {
| |
| 938 | //1055 CLS:PRINTCL$BR$:PRINTTAB((32-LEN(A$))/2)A$:PRINTBR$:RETURN | |
| 939 | cls(); | |
| 940 | print((__FlashStringHelper*)clStr); | |
| 941 | print((__FlashStringHelper*)brStr); | |
| 942 | printTab((32-strlen(aStr))/2); | |
| 943 | print(aStr); | |
| 944 | print((__FlashStringHelper*)brStr); | |
| 945 | } | |
| 946 | ||
| 947 | /*---------------------------------------------------------------------------*/ | |
| 948 | // The following functions mimic some of the Extended Color BASIC commands. | |
| 949 | ||
| 950 | // CLS | |
| 951 | // Clear the screen. | |
| 952 | void cls() | |
| 953 | {
| |
| 954 | print(); | |
| 955 | print(F("--------------CLS--------------"));
| |
| 956 | } | |
| 957 | ||
| 958 | // SOUND tone, duration | |
| 959 | // On the CoCo, tone (1-255), duration (1-255; 15=1 second). | |
| 960 | void sound(byte tone, byte duration) | |
| 961 | {
| |
| 962 | Serial.write(0x07); // BEL | |
| 963 | delay(duration*66.6); // Estimated delay. | |
| 964 | } | |
| 965 | ||
| 966 | /*---------------------------------------------------------------------------*/ | |
| 967 | // String functions. | |
| 968 | ||
| 969 | // STRING$(length, charcode) | |
| 970 | // Generate a string of length charcode chracters. | |
| 971 | void string(byte length, byte charcode) | |
| 972 | {
| |
| 973 | int i; | |
| 974 | ||
| 975 | for (i=0; i<length; i++) printCharSemi(charcode); | |
| 976 | } | |
| 977 | ||
| 978 | // RIGHT$(str, length) | |
| 979 | // Note: Modifies the passed in string, which is okay for our purpose but | |
| 980 | // would not be suitable as a generic replacement for RIGHT$. | |
| 981 | char *right(char *str, byte length) | |
| 982 | {
| |
| 983 | return &str[strlen(str)-length]; | |
| 984 | } | |
| 985 | ||
| 986 | // INSTR(first, str, substr) | |
| 987 | // Starting at pos, return position of substr in str, or 0 if not found. | |
| 988 | int instr(byte pos, char *str, char *substr) | |
| 989 | {
| |
| 990 | if (pos<1) return 0; | |
| 991 | return instr(aStr+pos, substr) + pos; | |
| 992 | } | |
| 993 | int instr(char *str, char *substr) | |
| 994 | {
| |
| 995 | char *ptr; | |
| 996 | ||
| 997 | ptr = strstr(str, substr); | |
| 998 | if (ptr==NULL) return 0; // No match? | |
| 999 | if (ptr==&str[strlen(str)]) return 0; // Matched the \0 at end of line? | |
| 1000 | return ptr-str+1; | |
| 1001 | } | |
| 1002 | ||
| 1003 | /*---------------------------------------------------------------------------*/ | |
| 1004 | // Input functions. | |
| 1005 | ||
| 1006 | #ifdef ENET_PORT | |
| 1007 | byte lineinput(char *cmdLine, byte len) | |
| 1008 | {
| |
| 1009 | return telnetInput(telnetClient, cmdLine, len); | |
| 1010 | } | |
| 1011 | #else | |
| 1012 | // LINE INPUT str | |
| 1013 | // Read string up to len bytes. This code comes from my Hayes AT Command | |
| 1014 | // parser, so the variables are named differently. | |
| 1015 | #define CR 13 | |
| 1016 | #define BEL 7 | |
| 1017 | #define BS 8 | |
| 1018 | #define CAN 24 | |
| 1019 | byte lineinput(char *cmdLine, byte len) | |
| 1020 | {
| |
| 1021 | int ch; | |
| 1022 | byte cmdLen = 0; | |
| 1023 | boolean done; | |
| 1024 | ||
| 1025 | done = false; | |
| 1026 | while(!done) | |
| 1027 | {
| |
| 1028 | - | while(myFile.available() && pos<count) { ch = myFile.read(); if (ch==CR) { buffer[pos] = '\0'; break; } if (ch>=32)
|
| 1028 | + | //ledBlink(); |
| 1029 | ||
| 1030 | ch = -1; // -1 is no data available | |
| 1031 | ||
| 1032 | if (Serial.available()>0) | |
| 1033 | {
| |
| 1034 | ch = Serial.read(); | |
| 1035 | } | |
| 1036 | else | |
| 1037 | {
| |
| 1038 | continue; // No data. Go back to the while()... | |
| 1039 | } | |
| 1040 | switch(ch) | |
| 1041 | {
| |
| 1042 | case -1: // No data available. | |
| 1043 | break; | |
| 1044 | ||
| 1045 | case CR: | |
| 1046 | print(); | |
| 1047 | cmdLine[cmdLen] = '\0'; | |
| 1048 | done = true; | |
| 1049 | break; | |
| 1050 | ||
| 1051 | /*case CAN: | |
| 1052 | print(F("[CAN]"));
| |
| 1053 | cmdLen = 0; | |
| 1054 | break;*/ | |
| 1055 | ||
| 1056 | case BS: | |
| 1057 | if (cmdLen>0) | |
| 1058 | {
| |
| 1059 | printCharSemi(BS); | |
| 1060 | printSemi(F(" "));
| |
| 1061 | printCharSemi(BS); | |
| 1062 | cmdLen--; | |
| 1063 | } | |
| 1064 | break; | |
| 1065 | ||
| 1066 | default: | |
| 1067 | // If there is room, store any printable characters in the cmdline. | |
| 1068 | if (cmdLen<len) | |
| 1069 | {
| |
| 1070 | if ((ch>31) && (ch<127)) // isprint(ch) does not work. | |
| 1071 | {
| |
| 1072 | printCharSemi(ch); | |
| 1073 | cmdLine[cmdLen] = ch; //toupper(ch); | |
| 1074 | cmdLen++; | |
| 1075 | } | |
| 1076 | } | |
| 1077 | else | |
| 1078 | {
| |
| 1079 | printCharSemi(BEL); // Overflow. Ring 'dat bell. | |
| 1080 | } | |
| 1081 | break; | |
| 1082 | } // end of switch(ch) | |
| 1083 | } // end of while(!done) | |
| 1084 | ||
| 1085 | return cmdLen; | |
| 1086 | } | |
| 1087 | #endif | |
| 1088 | ||
| 1089 | // INKEY$ | |
| 1090 | // Return character waiting (if any) from standard input (not ethernet). | |
| 1091 | char inkey() | |
| 1092 | {
| |
| 1093 | if (Serial.available()==0) return 0; | |
| 1094 | return Serial.read(); | |
| 1095 | } | |
| 1096 | ||
| 1097 | /*---------------------------------------------------------------------------*/ | |
| 1098 | ||
| 1099 | // File I/O | |
| 1100 | // Ideally, I would have created wrappers for the OPEN, READ, CLOSE commands, | |
| 1101 | // but I was in a hurry, so... | |
| 1102 | ||
| 1103 | //SD Card routines | |
| 1104 | #if defined(SD_PIN) | |
| 1105 | #define TEMP_SIZE 4 | |
| 1106 | #define FNAME_MAX (8+1+3+1) | |
| 1107 | boolean initSD() | |
| 1108 | {
| |
| 1109 | static bool sdInit = false; | |
| 1110 | ||
| 1111 | if (sdInit==true) return true; | |
| 1112 | ||
| 1113 | printSemi(F("Initializing SD card..."));
| |
| 1114 | pinMode(SD_PIN, OUTPUT); | |
| 1115 | if (!SD.begin(SD_PIN)) | |
| 1116 | {
| |
| 1117 | print(F("initialization failed."));
| |
| 1118 | return false; | |
| 1119 | } | |
| 1120 | print(F("initialization done."));
| |
| 1121 | sdInit = true; | |
| 1122 | ||
| 1123 | return true; | |
| 1124 | } | |
| 1125 | #endif | |
| 1126 | ||
| 1127 | //560 OPEN"I",#-1,"USERLOG":INPUT#-1,CL,NM:FORA=0TONM:INPUT#-1,NM$(A):NEXTA:CLOSE | |
| 1128 | void loadUserlog() | |
| 1129 | {
| |
| 1130 | #if defined(SD_PIN) | |
| 1131 | File myFile; | |
| 1132 | char tempStr[TEMP_SIZE]; | |
| 1133 | char filename[FNAME_MAX]; | |
| 1134 | ||
| 1135 | if (!initSD()) return; | |
| 1136 | ||
| 1137 | strncpy_P(filename, PSTR("USERLOG"), FNAME_MAX);
| |
| 1138 | ||
| 1139 | myFile = SD.open(filename, FILE_READ); | |
| 1140 | ||
| 1141 | if (myFile) | |
| 1142 | {
| |
| 1143 | printSemi(filename); | |
| 1144 | print(F(" opened."));
| |
| 1145 | fileReadln(myFile, tempStr, TEMP_SIZE); | |
| 1146 | cl = atoi(tempStr); | |
| 1147 | Serial.print(F("cl = "));
| |
| 1148 | - | while(tabPos<column) { printSemi(F(" ")); // Print, and increment tab position. } } // PRINT, // NOTE: DECB doesn't add a carraige return after a comma. void printComma() { printTab(tabPos + (16-(tabPos % 16))); } // PRINT "STRING"; // For normal strings in RAM. void printSemi(const char *string) { tabPos = tabPos + Serial.print(string); #if defined(ENET_PORT) telnetClient.print(string); #endif } // For strings in Flash. void printSemi(const __FlashStringHelper *string) { tabPos = tabPos + Serial.print(string); #if defined(ENET_PORT) telnetClient.print(string); #endif } // For printing a byte as a number (0-255). void printSemi(byte num) { Serial.print(F(" ")); tabPos = tabPos + Serial.print(num); Serial.print(F(" ")); tabPos = tabPos + 2; #if defined(ENET_PORT) telnetClient.print(F(" ")); telnetClient.print(num); telnetClient.print(F(" ")); #endif } // For printing a single character. void printCharSemi(char ch) { tabPos = tabPos + Serial.print(ch); #if defined(ENET_PORT) telnetClient.print(ch); #endif } // For printing a byte as a number with no spaces. void printNumSemi(byte num) { tabPos = tabPos + Serial.print(num); #if defined(ENET_PORT) telnetClient.print(num); #endif } // PRINT void print(void) { Serial.println(); #if defined(ENET_PORT) telnetClient.println(); #endif } // PRINT "STRING" void print(const char *string) { Serial.println(string); tabPos = 0; #if defined(ENET_PORT) telnetClient.println(string); #endif } void print(const __FlashStringHelper *string) { Serial.println(string); tabPos = 0; #if defined(ENET_PORT) telnetClient.println(string); #endif } // PRINT I void print(int num) { Serial.print(F(" ")); Serial.println(num); tabPos = 0; #if defined(ENET_PORT) telnetClient.print(F(" ")); telnetClient.println(num); #endif } // PRINT USING(format, number); // NOTE: This only emulates printing positive integers, which is the // only way it is used by this program. void printUsingSemi(char *format, byte num) { byte i; byte fmtDigits; byte numDigits; byte tempNum; i = 0; while(format[i]!='\0') { if (format[i]!='#') { printCharSemi(format[i]); i++; continue; } else { // Start counting the run of #s. // Find end of #'s to know how many to use. fmtDigits = 0; while(format[i]=='#' && format[i]!='\0') { fmtDigits++; i++; } // Now we know how many # (digits). tempNum = num; numDigits = 1; while(tempNum>10)
|
| 1148 | + | |
| 1149 | fileReadln(myFile, tempStr, TEMP_SIZE); | |
| 1150 | nm = atoi(tempStr); | |
| 1151 | Serial.print(F("nm = "));
| |
| 1152 | Serial.println(nm); | |
| 1153 | for (a=0; a<=nm; a++) | |
| 1154 | {
| |
| 1155 | fileReadln(myFile, nmArray[a], ULOG_SIZE); | |
| 1156 | Serial.print(a); | |
| 1157 | Serial.print(F(". "));
| |
| 1158 | Serial.println(nmArray[a]); | |
| 1159 | } | |
| 1160 | myFile.close(); | |
| 1161 | } | |
| 1162 | else | |
| 1163 | {
| |
| 1164 | printSemi(F("Error opening "));
| |
| 1165 | print(filename); | |
| 1166 | } | |
| 1167 | #else | |
| 1168 | print(F("(USERLOG would be loaded from tape here.)"));
| |
| 1169 | #endif | |
| 1170 | } | |
| 1171 | ||
| 1172 | //565 OPEN"I",#-1,"MSG BASE":INPUT#-1,MS:FORA=0TOMS-1:FORB=0TO10:INPUT#-1,MS$(A,B):NEXTB:NEXTA:CLOSE:RETURN | |
| 1173 | void loadMsgBase() | |
| 1174 | {
| |
| 1175 | #if defined(SD_PIN) | |
| 1176 | File myFile; | |
| 1177 | char tempStr[TEMP_SIZE]; | |
| 1178 | char filename[FNAME_MAX]; | |
| 1179 | ||
| 1180 | if (!initSD()) return; | |
| 1181 | ||
| 1182 | strncpy_P(filename, PSTR("MSGBASE"), FNAME_MAX);
| |
| 1183 | ||
| 1184 | myFile = SD.open(filename, FILE_READ); | |
| 1185 | if (myFile) | |
| 1186 | {
| |
| 1187 | printSemi(filename); | |
| 1188 | print(F(" opened."));
| |
| 1189 | fileReadln(myFile, tempStr, TEMP_SIZE); | |
| 1190 | ms = atoi(tempStr); | |
| 1191 | Serial.print("ms = ");
| |
| 1192 | Serial.println(ms); | |
| 1193 | for (a=0; a<=ms-1; a++) | |
| 1194 | {
| |
| 1195 | for (b=0; b<=MAX_LINE; b++) | |
| 1196 | {
| |
| 1197 | fileReadln(myFile, msArray[a][b], INPUT_SIZE); | |
| 1198 | Serial.print(F("msArray["));
| |
| 1199 | Serial.print(a); | |
| 1200 | Serial.print(F("]["));
| |
| 1201 | Serial.print(b); | |
| 1202 | Serial.print(F("] = "));
| |
| 1203 | Serial.println(msArray[a][b]); | |
| 1204 | } | |
| 1205 | } | |
| 1206 | myFile.close(); | |
| 1207 | } | |
| 1208 | else | |
| 1209 | {
| |
| 1210 | printSemi(F("Error opening "));
| |
| 1211 | print(filename); | |
| 1212 | } | |
| 1213 | #else | |
| 1214 | print(F("(MSGBASE would be loaded from tape here.)"));
| |
| 1215 | #endif | |
| 1216 | } | |
| 1217 | ||
| 1218 | #if defined(SD_PIN) | |
| 1219 | //byte fileReadln(File myFile, char *buffer, byte count) | |
| 1220 | {
| |
| 1221 | char ch; | |
| 1222 | int pos; | |
| 1223 | ||
| 1224 | pos = 0; | |
| 1225 | while(myFile.available() && pos<count) | |
| 1226 | {
| |
| 1227 | ch = myFile.read(); | |
| 1228 | if (ch==CR) | |
| 1229 | {
| |
| 1230 | buffer[pos] = '\0'; | |
| 1231 | break; | |
| 1232 | } | |
| 1233 | - | extern int __heap_start, *__brkval; |
| 1233 | + | if (ch>=32) |
| 1234 | - | int v; |
| 1234 | + | |
| 1235 | - | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); |
| 1235 | + | |
| 1236 | buffer[pos] = ch; | |
| 1237 | pos++; | |
| 1238 | } | |
| 1239 | } | |
| 1240 | if (pos>=count) buffer[pos] = '\0'; | |
| 1241 | //Serial.println(); | |
| 1242 | return pos; | |
| 1243 | } | |
| 1244 | #endif | |
| 1245 | ||
| 1246 | //610 OPEN"O",#-1,"USERLOG":PRINT#-1,CL,NM:FORA=0TONM:PRINT#-1,NM$(A):NEXTA:CLOSE | |
| 1247 | void saveUserlog() | |
| 1248 | {
| |
| 1249 | #if defined(SD_PIN) | |
| 1250 | File myFile; | |
| 1251 | char filename[FNAME_MAX]; | |
| 1252 | ||
| 1253 | if (!initSD()) return; | |
| 1254 | ||
| 1255 | strncpy_P(filename, PSTR("USERLOG"), FNAME_MAX);
| |
| 1256 | ||
| 1257 | if (SD.exists(filename)==true) SD.remove(filename); | |
| 1258 | ||
| 1259 | myFile = SD.open(filename, FILE_WRITE); | |
| 1260 | if (myFile) | |
| 1261 | {
| |
| 1262 | printSemi(filename); | |
| 1263 | print(F(" created."));
| |
| 1264 | myFile.println(cl); | |
| 1265 | Serial.print(F("cl = "));
| |
| 1266 | Serial.println(cl); | |
| 1267 | myFile.println(nm); | |
| 1268 | Serial.print(F("nm = "));
| |
| 1269 | Serial.println(nm); | |
| 1270 | for (a=0; a<=nm; a++) | |
| 1271 | {
| |
| 1272 | myFile.println(nmArray[a]); | |
| 1273 | Serial.print(a); | |
| 1274 | Serial.print(F(". "));
| |
| 1275 | Serial.println(nmArray[a]); | |
| 1276 | } | |
| 1277 | myFile.close(); | |
| 1278 | } | |
| 1279 | else | |
| 1280 | {
| |
| 1281 | print(F("Error creating file."));
| |
| 1282 | } | |
| 1283 | #else | |
| 1284 | print(F("save USERLOG"));
| |
| 1285 | #endif | |
| 1286 | } | |
| 1287 | ||
| 1288 | - | //30 A$=INKEY$:IFA$=""THEN30ELSEPRINT@408,A$:LN=VAL(A$):IFLN8THENSOUND50,1:GOTO25 |
| 1288 | + | |
| 1289 | void saveMsgBase() | |
| 1290 | {
| |
| 1291 | #if defined(SD_PIN) | |
| 1292 | File myFile; | |
| 1293 | char filename[FNAME_MAX]; | |
| 1294 | ||
| 1295 | if (!initSD()) return; | |
| 1296 | ||
| 1297 | strncpy_P(filename, PSTR("MSGBASE"), FNAME_MAX);
| |
| 1298 | ||
| 1299 | if (SD.exists(filename)==true) SD.remove(filename); | |
| 1300 | ||
| 1301 | myFile = SD.open(filename, FILE_WRITE); | |
| 1302 | if (myFile) | |
| 1303 | {
| |
| 1304 | printSemi(filename); | |
| 1305 | print(F(" created."));
| |
| 1306 | myFile.println(ms); | |
| 1307 | for (a=0; a<=ms-1; a++) | |
| 1308 | {
| |
| 1309 | for (b=0; b<=MAX_LINE; b++) | |
| 1310 | {
| |
| 1311 | myFile.println(msArray[a][b]); | |
| 1312 | Serial.print(F("msArray["));
| |
| 1313 | Serial.print(a); | |
| 1314 | Serial.print(F("]["));
| |
| 1315 | Serial.print(b); | |
| 1316 | Serial.print(F("] = "));
| |
| 1317 | Serial.println(msArray[a][b]); | |
| 1318 | } | |
| 1319 | } | |
| 1320 | myFile.close(); | |
| 1321 | } | |
| 1322 | else | |
| 1323 | - | //285 C=C+1:PRINT#-2,TAB(B)MS$(A,C):IFMS$(A,C)=""THEN290ELSEIFC20THENPRINT@198,NM$ELSENM$=A$ |
| 1323 | + | |
| 1324 | print(F("Error creating file."));
| |
| 1325 | - | //375 PRINT@262,;:LINEINPUTA$:B=VAL(A$):IFB9THENPRINT@261,LV ELSELV=B |
| 1325 | + | |
| 1326 | #else | |
| 1327 | - | //385 PRINT@456," JUMP TO USER # ";:LINEINPUTA$:B=VAL(A$):IFBNM THENSOUND1,5:GOTO335ELSEA=B:GOTO320 |
| 1327 | + | |
| 1328 | - | //390 A=A-1:IFA<0THENA=NM //391 GOTO315 //395 A=A+1:IFA>NM THENA=0 |
| 1328 | + | |
| 1329 | } | |
| 1330 | ||
| 1331 | /*---------------------------------------------------------------------------*/ | |
| 1332 | // Print (output) routines. | |
| 1333 | - | //415 PRINT@96,"DELETE MESSAGE # 1 -"MS":";:LINEINPUTA$:A=VAL(A$):IFAMS THEN15 |
| 1333 | + | |
| 1334 | // For TAB to work, we need to track where we think we are on the line. | |
| 1335 | byte tabPos = 0; | |
| 1336 | ||
| 1337 | // We want to simulate the following: | |
| 1338 | // PRINT "HELLO" -- string, with carraige return at end of line | |
| 1339 | // PRINT A -- number (space before and after), with carraige return | |
| 1340 | // PRINT "HELLO"; -- no carraige return | |
| 1341 | // PRINT TAB(5); -- tab to position 5 | |
| 1342 | // PRINT "A","B" -- tab to column 16 (on 32-column screen) | |
| 1343 | ||
| 1344 | // Due to various types of strings on Arduino (in memory or Flash), we will | |
| 1345 | // have to duplicate some functions to have versions that take the other | |
| 1346 | // types of strings. | |
| 1347 | ||
| 1348 | // printTypeSemi() routines will not put a carraige return at the end. | |
| 1349 | ||
| 1350 | // PRINT TAB(column); | |
| 1351 | void printTab(byte column) | |
| 1352 | {
| |
| 1353 | while(tabPos<column) | |
| 1354 | {
| |
| 1355 | printSemi(F(" ")); // Print, and increment tab position.
| |
| 1356 | } | |
| 1357 | } | |
| 1358 | ||
| 1359 | // PRINT, | |
| 1360 | // NOTE: DECB doesn't add a carraige return after a comma. | |
| 1361 | void printComma() | |
| 1362 | {
| |
| 1363 | printTab(tabPos + (16-(tabPos % 16))); | |
| 1364 | } | |
| 1365 | ||
| 1366 | // PRINT "STRING"; | |
| 1367 | // For normal strings in RAM. | |
| 1368 | void printSemi(const char *string) | |
| 1369 | {
| |
| 1370 | tabPos = tabPos + Serial.print(string); | |
| 1371 | #if defined(ENET_PORT) | |
| 1372 | telnetClient.print(string); | |
| 1373 | #endif | |
| 1374 | } | |
| 1375 | // For strings in Flash. | |
| 1376 | void printSemi(const __FlashStringHelper *string) | |
| 1377 | {
| |
| 1378 | tabPos = tabPos + Serial.print(string); | |
| 1379 | #if defined(ENET_PORT) | |
| 1380 | telnetClient.print(string); | |
| 1381 | #endif | |
| 1382 | } | |
| 1383 | // For printing a byte as a number (0-255). | |
| 1384 | void printSemi(byte num) | |
| 1385 | {
| |
| 1386 | Serial.print(F(" "));
| |
| 1387 | tabPos = tabPos + Serial.print(num); | |
| 1388 | Serial.print(F(" "));
| |
| 1389 | tabPos = tabPos + 2; | |
| 1390 | #if defined(ENET_PORT) | |
| 1391 | telnetClient.print(F(" "));
| |
| 1392 | telnetClient.print(num); | |
| 1393 | telnetClient.print(F(" "));
| |
| 1394 | #endif | |
| 1395 | } | |
| 1396 | // For printing a single character. | |
| 1397 | void printCharSemi(char ch) | |
| 1398 | {
| |
| 1399 | tabPos = tabPos + Serial.print(ch); | |
| 1400 | #if defined(ENET_PORT) | |
| 1401 | telnetClient.print(ch); | |
| 1402 | #endif | |
| 1403 | } | |
| 1404 | // For printing a byte as a number with no spaces. | |
| 1405 | void printNumSemi(byte num) | |
| 1406 | {
| |
| 1407 | tabPos = tabPos + Serial.print(num); | |
| 1408 | #if defined(ENET_PORT) | |
| 1409 | telnetClient.print(num); | |
| 1410 | #endif | |
| 1411 | } | |
| 1412 | ||
| 1413 | ||
| 1414 | void print(void) | |
| 1415 | {
| |
| 1416 | Serial.println(); | |
| 1417 | #if defined(ENET_PORT) | |
| 1418 | telnetClient.println(); | |
| 1419 | #endif | |
| 1420 | } | |
| 1421 | ||
| 1422 | // PRINT "STRING" | |
| 1423 | void print(const char *string) | |
| 1424 | {
| |
| 1425 | Serial.println(string); | |
| 1426 | tabPos = 0; | |
| 1427 | #if defined(ENET_PORT) | |
| 1428 | telnetClient.println(string); | |
| 1429 | #endif | |
| 1430 | } | |
| 1431 | void print(const __FlashStringHelper *string) | |
| 1432 | {
| |
| 1433 | Serial.println(string); | |
| 1434 | tabPos = 0; | |
| 1435 | #if defined(ENET_PORT) | |
| 1436 | telnetClient.println(string); | |
| 1437 | #endif | |
| 1438 | } | |
| 1439 | ||
| 1440 | // PRINT I | |
| 1441 | void print(int num) | |
| 1442 | {
| |
| 1443 | Serial.print(F(" "));
| |
| 1444 | Serial.println(num); | |
| 1445 | tabPos = 0; | |
| 1446 | #if defined(ENET_PORT) | |
| 1447 | telnetClient.print(F(" "));
| |
| 1448 | telnetClient.println(num); | |
| 1449 | #endif | |
| 1450 | } | |
| 1451 | ||
| 1452 | // PRINT USING(format, number); | |
| 1453 | // NOTE: This only emulates printing positive integers, which is the | |
| 1454 | // only way it is used by this program. | |
| 1455 | void printUsingSemi(char *format, byte num) | |
| 1456 | {
| |
| 1457 | byte i; | |
| 1458 | byte fmtDigits; | |
| 1459 | byte numDigits; | |
| 1460 | byte tempNum; | |
| 1461 | ||
| 1462 | i = 0; | |
| 1463 | while(format[i]!='\0') | |
| 1464 | {
| |
| 1465 | if (format[i]!='#') {
| |
| 1466 | printCharSemi(format[i]); | |
| 1467 | i++; | |
| 1468 | continue; | |
| 1469 | } | |
| 1470 | else | |
| 1471 | {
| |
| 1472 | // Start counting the run of #s. | |
| 1473 | // Find end of #'s to know how many to use. | |
| 1474 | fmtDigits = 0; | |
| 1475 | while(format[i]=='#' && format[i]!='\0') | |
| 1476 | {
| |
| 1477 | fmtDigits++; | |
| 1478 | i++; | |
| 1479 | } | |
| 1480 | // Now we know how many # (digits). | |
| 1481 | tempNum = num; | |
| 1482 | numDigits = 1; | |
| 1483 | while(tempNum>10) | |
| 1484 | {
| |
| 1485 | tempNum = tempNum/10; | |
| 1486 | numDigits++; | |
| 1487 | } | |
| 1488 | while(numDigits<fmtDigits) | |
| 1489 | {
| |
| 1490 | printSemi(F(" "));
| |
| 1491 | fmtDigits--; | |
| 1492 | } | |
| 1493 | printNumSemi(num); | |
| 1494 | } | |
| 1495 | } | |
| 1496 | } | |
| 1497 | ||
| 1498 | /*---------------------------------------------------------------------------*/ | |
| 1499 | // Show some stuff functions. | |
| 1500 | ||
| 1501 | // Emit some configuration information. | |
| 1502 | void showConfig() | |
| 1503 | {
| |
| 1504 | print((__FlashStringHelper*)brStr); | |
| 1505 | print(F("*ALL RAM* Configuration:"));
| |
| 1506 | printSemi(F("Userlog size :"));
| |
| 1507 | print(MAX_USERS+1); | |
| 1508 | printSemi(F("Input size :"));
| |
| 1509 | print(INPUT_SIZE); | |
| 1510 | printSemi(F("Username size:"));
| |
| 1511 | print(NAME_SIZE); | |
| 1512 | printSemi(F("Password size:"));
| |
| 1513 | print(PSWD_SIZE); | |
| 1514 | printSemi(F("Msg base size:"));
| |
| 1515 | print(MAX_MSGS+1); | |
| 1516 | printSemi(F("Message lines:"));
| |
| 1517 | print(MAX_LINE+1); | |
| 1518 | #if defined(SD_PIN) | |
| 1519 | print(F("SD card : Enabled"));
| |
| 1520 | #endif | |
| 1521 | #if defined(ENET_PORT) | |
| 1522 | print(F("Ethernet : Enabled"));
| |
| 1523 | #endif | |
| 1524 | printSemi(F("ESTIMATED MEM:"));
| |
| 1525 | printSemi(ULOG_MEM + MBASE_MEM); | |
| 1526 | print(F("bytes."));
| |
| 1527 | printSemi(F("Free RAM :"));
| |
| 1528 | print(freeRam()); | |
| 1529 | print((__FlashStringHelper*)brStr); | |
| 1530 | } | |
| 1531 | ||
| 1532 | void showLoginMessage() | |
| 1533 | {
| |
| 1534 | print(F("\nYou are connected to an Arduino UNO R3, a small computer thing you can buy\n"
| |
| 1535 | "from Radio Shack for $29.99 (or around $22 online). It has 2K of RAM and\n" | |
| 1536 | "32K of Flash for program storage. It has a SainSmart Ethernet Shield ($17.99)\n" | |
| 1537 | "attached to it. The software running here is a line-by-line port of my\n" | |
| 1538 | "*ALL RAM* BBS program written in 1983. The original Extended Color BASIC\n" | |
| 1539 | "code was converted as literally as possible to Arduino C. It's a travesty.\n" | |
| 1540 | "\n" | |
| 1541 | "This BBS program was designed to run on a cassette based TRS-80 Color\n" | |
| 1542 | "Computer with 32K of RAM. All messages and users were stored in memory.\n" | |
| 1543 | "Obviously, with only 2K of RAM, this is not possible, so this version has\n" | |
| 1544 | "been configured to allow only a few users and a teensy tiny message base\n" | |
| 1545 | "(smaller than Twitter posts!). Enjoy the experiment!\n" | |
| 1546 | "\n" | |
| 1547 | "(If userlog is full, use the Sysop password 'TEST'.)")); | |
| 1548 | } | |
| 1549 | ||
| 1550 | void showCoCoHeader() | |
| 1551 | {
| |
| 1552 | cls(); | |
| 1553 | print(F("EXTENDED COLOR BASIC 1.1\n"
| |
| 1554 | "COPYRIGHT (C) 1982 BY TANDY\n" | |
| 1555 | "UNDER LICENSE FROM MICROSOFT\n" | |
| 1556 | "\n" | |
| 1557 | "OK\n" | |
| 1558 | "CLOAD\"ALLRAM\"\n" | |
| 1559 | "RUN")); | |
| 1560 | } | |
| 1561 | ||
| 1562 | /*---------------------------------------------------------------------------*/ | |
| 1563 | ||
| 1564 | // Debug and utility functions. | |
| 1565 | // | |
| 1566 | ||
| 1567 | unsigned int freeRam() {
| |
| 1568 | extern int __heap_start, *__brkval; | |
| 1569 | int v; | |
| 1570 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); | |
| 1571 | } | |
| 1572 | ||
| 1573 | void showFreeRam() | |
| 1574 | {
| |
| 1575 | printSemi(F("Free RAM:"));
| |
| 1576 | print(freeRam()); | |
| 1577 | } | |
| 1578 | ||
| 1579 | /*---------------------------------------------------------------------------*/ | |
| 1580 | ||
| 1581 | void showUserlog() | |
| 1582 | {
| |
| 1583 | int i; | |
| 1584 | printSemi(F("Users: "));
| |
| 1585 | print(nm); | |
| 1586 | for (i=0; i<=nm; i++) {
| |
| 1587 | printSemi(i); | |
| 1588 | printSemi(F(". "));
| |
| 1589 | print(nmArray[i]); | |
| 1590 | } | |
| 1591 | } | |
| 1592 | ||
| 1593 | void showMessageBase() | |
| 1594 | {
| |
| 1595 | int i,j; | |
| 1596 | ||
| 1597 | for (int i=0; i<ms; i++) | |
| 1598 | {
| |
| 1599 | for (int j=0; j<=MAX_LINE; j++) | |
| 1600 | {
| |
| 1601 | printSemi(F("msArray["));
| |
| 1602 | printSemi(i); | |
| 1603 | printSemi(F(","));
| |
| 1604 | printSemi(j); | |
| 1605 | printSemi(F("] = "));
| |
| 1606 | print(msArray[i][j]); | |
| 1607 | } | |
| 1608 | } | |
| 1609 | } | |
| 1610 | ||
| 1611 | ||
| 1612 | /*---------------------------------------------------------------------------*/ | |
| 1613 | ||
| 1614 | //0 REM *ALL RAM* BBS Editor 1.0 | |
| 1615 | //1 REM Shareware / (C) 1983 | |
| 1616 | //2 REM By Allen Huffman | |
| 1617 | //3 REM 110 Champions Dr, #811 | |
| 1618 | //4 REM Lufkin, TX 75901 | |
| 1619 | //5 FORA=0TO8:READA$:POKE1024+A,VAL("&H"+A$):NEXTA:EXEC1024:DATAC6,1,96,BC,1F,2,7E,96,A3
| |
| 1620 | //10 CLEAR21000:DIMNM$(200),MS$(19,10),A$,F$,S$,T$,NM$,PW$,A,B,C,LN,LV,MS,NM,PR:PR=80 | |
| 1621 | //15 CLS:PRINTTAB(3)"*ALL RAM* EDITOR COMMANDS:":printING$(32,45) | |
| 1622 | //20 PRINTTAB(4)"1. CREATE USERLOG",TAB(4)"2. LOAD USERLOG/MSG BASE",TAB(4)"3. SAVE USERLOG/MSG BASE",TAB(4)"4. PRINT USERLOG",TAB(4)"5. PRINT MESSAGES",TAB(4)"6. EDIT USERS",TAB(4)"7. KILL MESSAGES",TAB(4)"8. QUIT" | |
| 1623 | //25 PRINT@392,"ENTER FUNCTION :" | |
| 1624 | //30 A$=INKEY$:IFA$=""THEN30ELSEPRINT@408,A$:LN=VAL(A$):IFLN<1ORLN>8THENSOUND50,1:GOTO25 | |
| 1625 | //35 SOUND200,1:ONLN GOTO55,105,155,205,255,305,405,40 | |
| 1626 | //40 STOP | |
| 1627 | //50 'Create Userlog | |
| 1628 | //55 CLS:PRINTTAB(7)"SYSOP INFORMATION:":printING$(32,45) | |
| 1629 | //60 PRINT@128,"SYSOP'S NAME: (20 CHARACTERS)>";:LINEINPUTA$:IFA$=""ORLEN(A$)>20THENSOUND50,1:GOTO15ELSENM$=A$ | |
| 1630 | //65 PRINT@192,"PASSWORD : (8 CHARACTERS)>";:LINEINPUTA$:IFA$=""ORLEN(A$)>8THENSOUND50,1:GOTO15ELSEPW$=A$ | |
| 1631 | //70 PRINT@297,"*VERIFY ENTRY*":PRINT:PRINT"NAME :"NM$:PRINT"PSWD :"PW$:PRINT@456,"IS THIS CORRECT?"; | |
| 1632 | //75 LINEINPUTA$:IFLEFT$(A$,1)<>"Y"THENSOUND50,1:GOTO55 | |
| 1633 | //80 NM$(0)=NM$+"\"+PW$+"9":GOTO15 | |
| 1634 | //100 'Load Userlog/Msg Base | |
| 1635 | //105 CLS:PRINTTAB(5)"LOAD USERLOG/MSG BASE:":printING$(32,45) | |
| 1636 | //110 LINEINPUT" READY TAPE, THEN PRESS ENTER:";A$:PRINT@168,"...ONE MOMENT..." | |
| 1637 | //115 OPEN"I",#-1,"USERLOG":PRINT@232,"LOADING USERLOG":INPUT#-1,CL,NM:FORA=0TONM:INPUT#-1,NM$(A):NEXTA:CLOSE | |
| 1638 | //120 OPEN"I",#-1,"MSG BASE":PRINT@240,"MSG BASE":INPUT#-1,MS:FORA=0TOMS-1:FORB=0TO10:INPUT#-1,MS$(A,B):NEXTB:NEXTA:CLOSE:GOTO15 | |
| 1639 | //150 'Save Userlog/Msg Base | |
| 1640 | //155 CLS:PRINTTAB(5)"SAVE USERLOG/MSG BASE:":printING$(32,45) | |
| 1641 | //160 LINEINPUT" READY TAPE, THEN PRESS ENTER:";A$:PRINT@168,"...ONE MOMENT...":MOTORON:FORA=1TO1000:NEXTA | |
| 1642 | //165 PRINT@232,"SAVING USERLOG":OPEN"O",#-1,"USERLOG":PRINT#-1,CL,NM:FORA=0TONM:PRINT#-1,NM$(A):NEXTA:CLOSE | |
| 1643 | //170 PRINT@240,"MSG BASE":OPEN"O",#-1,"MSG BASE":PRINT#-1,MS:FORA=0TOMS-1:FORB=0TO10:PRINT#-1,MS$(A,B):NEXTB:NEXTA:CLOSE:GOTO15 | |
| 1644 | //200 'Print Userlog | |
| 1645 | //205 IFNM$(0)=""THENPRINT@454,"*USERLOG NOT LOADED*":SOUND50,1:GOTO25 | |
| 1646 | //210 CLS:PRINTTAB(9)"PRINT USERLOG:":printING$(32,45) | |
| 1647 | //215 LINEINPUT" PRESS ENTER WHEN READY:";A$:PRINT@169,"...PRINTING..." | |
| 1648 | //220 PRINT#-2,TAB((PR-30)/2)"[*ALL RAM* BBS System Userlog]":PRINT#-2,"":PRINT#-2,TAB((PR-46)/2)"[###] [ NAME ] [PASSWORD] [L]" | |
| 1649 | //225 FORA=0TONM:A$=NM$(A):B=INSTR(A$,"\"):NM$=LEFT$(A$,B-1):PW$=MID$(A$,B+1,LEN(A$)-B-1):LV=VAL(RIGHT$(A$,1)) | |
| 1650 | //230 A$="000........................................0":B=LEN(STR$(A))-1:MID$(A$,4-B,B)=RIGHT$(STR$(A),B):MID$(A$,8,LEN(NM$))=NM$:MID$(A$,32,LEN(PW$))=PW$:MID$(A$,44,1)=RIGHT$(STR$(LV),1) | |
| 1651 | //235 PRINT@238,A:PRINT#-2,TAB((PR-44)/2)A$:NEXTA:GOTO15 | |
| 1652 | //250 'Print Messages | |
| 1653 | //255 IFMS$(0,0)=""THENPRINT@454,"*MSG BASE NOT LOADED*":SOUND50,1:GOTO25 | |
| 1654 | //260 CLS:PRINTTAB(8)"PRINT MESSAGES:":printING$(32,45) | |
| 1655 | //265 LINEINPUT" PRESS ENTER WHEN READY:";A$:PRINT@169,"...PRINTING..." | |
| 1656 | //270 PRINT#-2,TAB((PR-30)/2)"[*ALL RAM* BBS System Messages]":PRINT#-2,"" | |
| 1657 | //275 FORA=0TOMS-1:A$=MS$(A,0):B=INSTR(A$,"\"):C=INSTR(B+1,A$,"\"):T$=LEFT$(A$,B-1):F$=MID$(A$,B+1,C-B-1):S$=RIGHT$(A$,LEN(A$)-C) | |
| 1658 | //280 PRINT@238,A+1:B=(PR-64)/2:PRINT#-2,TAB(B)"Message #"A:PRINT#-2,TAB(B)"TO :"T$:PRINT#-2,TAB(B)"FR :"F$:PRINT#-2,TAB(B)"SB :"S$:PRINT#-2,STRING$(64,45):C=0 | |
| 1659 | //285 C=C+1:PRINT#-2,TAB(B)MS$(A,C):IFMS$(A,C)=""THEN290ELSEIFC<10THEN285 | |
| 1660 | //290 PRINT#-2,"":NEXTA:GOTO15 | |
| 1661 | //300 'Edit Users | |
| 1662 | //305 IFNM$(0)=""THENPRINT@454,"*USERLOG NOT LOADED*":SOUND50,1:GOTO25 | |
| 1663 | //310 CLS:PRINTTAB(10)"EDIT USERS:":printING$(32,45):A=0 | |
| 1664 | //315 PRINT@70,"USERS ON SYSTEM:"NM | |
| 1665 | //320 A$=NM$(A):B=INSTR(A$,"\"):NM$=LEFT$(A$,B-1):PW$=MID$(A$,B+1,LEN(A$)-B-1):LV=VAL(RIGHT$(A$,1)) | |
| 1666 | //325 PRINT@128,"USER #"A:PRINT:PRINT"NAME: "NM$:PRINT"PSWD: "PW$:PRINT"LVL :"LV | |
| 1667 | //330 PRINT@320,STRING$(32,45)TAB(4)"D-LET UP-BACK J-UMP",TAB(4)"E-DIT DN-NEXT M-ENU" | |
| 1668 | //335 PRINT@456,"ENTER FUNCTION :" | |
| 1669 | //340 A$=INKEY$:IFA$=""THEN340ELSEPRINT@472,A$;:LN=INSTR("DEJM"+CHR$(94)+CHR$(10),A$):IFLN=0THENSOUND50,1:GOTO335
| |
| 1670 | //345 SOUND200,1:ONLN GOTO350,365,385,15,390,395 | |
| 1671 | //350 IFA=0THENSOUND1,5:GOTO335 | |
| 1672 | //355 IFA=NM THENNM=NM-1:A=A-1:GOTO315 | |
| 1673 | //360 FORB=A TONM:NM$(B)=NM$(B+1):NEXTB:NM=NM-1:GOTO315 | |
| 1674 | //365 PRINT@198,;:LINEINPUTA$:IFA$=""ORLEN(A$)>20THENPRINT@198,NM$ELSENM$=A$ | |
| 1675 | //370 PRINT@230,;:LINEINPUTA$:IFA$=""ORLEN(A$)>8THENPRINT@230,PW$ELSEPW$=A$ | |
| 1676 | //375 PRINT@262,;:LINEINPUTA$:B=VAL(A$):IFB<1ORB>9THENPRINT@261,LV ELSELV=B | |
| 1677 | //380 NM$(A)=NM$+"\"+PW$+RIGHT$(STR$(LV),1):GOTO335 | |
| 1678 | //385 PRINT@456," JUMP TO USER # ";:LINEINPUTA$:B=VAL(A$):IFB<0ORB>NM THENSOUND1,5:GOTO335ELSEA=B:GOTO320 | |
| 1679 | //390 A=A-1:IFA<0THENA=NM | |
| 1680 | //391 GOTO315 | |
| 1681 | //395 A=A+1:IFA>NM THENA=0 | |
| 1682 | //396 GOTO315 | |
| 1683 | //400 'Kill Messages | |
| 1684 | //405 IFMS$(0,0)=""THENPRINT@454,"*MSG BASE NOT LOADED*":SOUND50,1:GOTO25 | |
| 1685 | //410 CLS:PRINTTAB(9)"KILL MESSAGES:":ING$(32,45) | |
| 1686 | //415 PRINT@96,"DELETE MESSAGE # 1 -"MS":";:LINEINPUTA$:A=VAL(A$):IFA<1ORA>MS THEN15 | |
| 1687 | //420 A$=MS$(A-1,0):B=INSTR(A$,"\"):C=INSTR(B+1,A$,"\"):T$=LEFT$(A$,B-1):F$=MID$(A$,B+1,C-B-1):S$=RIGHT$(A$,LEN(A$)-C) | |
| 1688 | //425 PRINT:PRINT"TO: "T$:PRINT"FR: "F$:PRINT"SB: "S$ | |
| 1689 | //430 PRINT:LINEINPUT"DELETE THIS?";A$:IFLEFT$(A$,1)<>"Y"THEN410 | |
| 1690 | //435 IFA=MS THENMS=MS-1:GOTO410 | |
| 1691 | //440 FORB=A-1 TOMS-2:FORC=0TO10:MS$(B,C)=MS$(B+1,C):NEXTC:NEXTB:MS=MS-1:GOTO410 | |
| 1692 | ||
| 1693 | // End of file. |