/* DRAIN, Version 3: spin dry modification.

     My thanks to James R. Maynard III, a good friend, fellow
     firefighter and ham for taking on the suggestions (and
     accusations that he wrote 'DRAIN1') and improved it while
     also providing us wanna-be programmers with the source code
     to his project. With that and a little help from George
     Henderson (showing me how to use TurboC) I 'hacked' a little
     and came up with the fixes to non-incremental spin-dry.
     Some say they like this girgle better (ver2), maybe so. How
     the original author did the good flush the first time we
     have yet to figure out.
     Chock this up to good old non-virus software. This is a CLEAN
     prank...and damn those who don't continue to include the Source
     code, and especially those who take this reputable clean file
     and screw up someone's system with it.....if you do -
     may all your floppies flop and your hard drive go limp, ah,er
     soft forever !
     My wishes for keeping the original file/comments intact, and any
     changes only additive, for the better, accompany those of
     Mr. Maynard...
     Grapevine P.C. Associates
     Jim Aspinwall, The Source, AAJ696
*/

/* Drain, version 2: better prompt handling.

     I don't claim credit for this idea, and the original perpretrator
     is lost in the mists of time...but I liked the idea. The original
     program only had one problem, though: It ignored the user's
     PROMPT setting. That made it somewhat transparent, since not many
     people any more run from drive A, and darned few of them use a
     yellow prompt! I got Turbo C, and decided this would be a good
     learning project.

     This program is (C) Copyright 1987, James R. Maynard III
                             6027 Leafwood Circle
                             League City, Texas 77573
     This program may be copied and distributed freely, with only
     one restriction: These comments must not be modified. (After
     all, we all would like to be known for SOMETHING!) If you come
     up with improvements, please let me know so I can enjoy them
     too. Send me mail at the above address, or to my GEnie mailbox
     (JAYMAYNARD), my Compu$erve mailbox (71036,1603), or my FidoNode
     (Graf Spee, 106/64). I hope to have a usenet address soon...
*/

#include <stdio.h>
#include <dir.h>
#include <math.h>
#include <bios.h>
#include <dos.h>

#define MAXPROMPT 80

main()
{
     char promptstr[MAXPROMPT];
     void getprompt(), clrscr(), draindrive();

     getprompt(promptstr);    /* get the user's prompt, or default */
     clrscr();      /* clear the screen? */
     printf("%s",promptstr);  /* write the bogus prompt */
     getch();       /* wait for a key */
     draindrive();       /* do the draining */
}

void getprompt(str)
char *str;
{
     char *envprompt, *getenv(), promptchar;
     int putpath(), putdate(), puttime(), putver();

     if ((envprompt = getenv("PROMPT")) != NULL) {
          for ( ; (promptchar = *envprompt) != 0; envprompt++, str++) {
               if (promptchar == '$') {
                    promptchar = *++envprompt;
                    switch (promptchar) {
                         case '$': *str = '$';
                                break;
                         case '_': *str = '\n';
                                break;
                         case 'T':
                         case 't': str += puttime(str);
                                break;
                         case 'D':
                         case 'd': str += putdate(str);
                                break;
                         case 'N':
                         case 'n': *str = getdisk()+'A';
                                break;
                         case 'G':
                         case 'g': *str = '>';
                                break;
                         case 'L':
                         case 'l': *str = '<';
                                break;
                         case 'B':
                         case 'b': *str = '|';
                                break;
                         case 'H':
                         case 'h': *str = '\b';
                                break;
                         case 'E':
                         case 'e': *str = '\x1B';
                                break;
                         case 'Q':
                         case 'q': *str = '=';
                                break;
                         case 'P':
                         case 'p': str += putpath(str);
                                break;
                         case 'V':
                         case 'v': str += putver(str);
                                break;
                    }
               }
               else *str = promptchar;
          }
          *str = '\0';
     }
     else {
          *str++ = getdisk() + 'A';
          strcpy(str,">");
     }
}

int putpath(char *str)
{
     char *curdir;
     int pathlen;

     curdir = getcwd(NULL,80);
     strcpy(str,curdir);
     pathlen = strlen(curdir) - 1;
     free(curdir);
     return(pathlen);
}

int putver(char *str)
{
     int i;
     FILE *verfile;
     char version[MAXPROMPT];

     system("ver >$$drain$.$$$");
     verfile = fopen("$$drain$.$$$","r");
     fgets(version,MAXPROMPT,verfile);
     fgets(version,MAXPROMPT,verfile);
     strcpy(str,version);
     fclose(verfile);
     unlink("$$drain$.$$$");
     return(strlen(version) - 2);
}

int puttime(char *str)
{
     int i;
     struct time now;

     gettime(&now);
     sprintf(str,"%2d:%02d:%02d.%02d",now.ti_hour,now.ti_min,now.ti_sec,
          now.ti_hund);
     return(10);
}

int putdate(char *str)
{
     int i;
     long secs_now;
     struct date today;

     getdate(&today);
     time(&secs_now);
     strncpy(str,ctime(&secs_now),4);
     str += 4;
     sprintf(str,"%2d-%02d-%04d",today.da_mon,today.da_day,today.da_year);
     return(13);
}

void clrscr()
{
     union REGS regs;

     regs.h.ah = 15; /* get video mode */
     int86(0x10,&regs,&regs);
     regs.h.ah = 0;  /* set video mode, left in AL by previous call */
     int86(0x10,&regs,&regs);
}

void draindrive()
{
     void tone(int hertz, int ticks);
     void slidetone(int start, int finish, int inc);
     int freq, i;
     char curdrive;

     curdrive = getdisk() + 'A';
     puts(" *** SYSTEM ERROR ***");
     printf("Water has been detected in drive %c. Drive cleanup",curdrive);
     puts(" in progress.\nThis will take a few moments.");
     puts("\nDrain phase beginning...");
     for (i = 7000; i > 50; i *= 0.96) {
          freq = rand() / 32768.0 * i + 50.0;
          tone(freq,1);
     }
     puts("Drain phase complete.\n");
     sleep(2);
     puts("Spin dry phase beginning...");
     for (i = 100; i <= 1000; i += 100) {
          slidetone(i - 100,i,1);
          tone(i,0);
     }
     tone(i-100,16);
     slidetone(900,0,-5);
     puts("Spin dry phase complete.\n\nDrive cleanup complete.");
     puts("You may continue your work.");
}

void tone(int hertz, int ticks)
{
     long begintime;
     char bits;
     int count;

     begintime = biostime(0,0L);
     bits = inportb(0x61);
     count = 1193280 / hertz;
     outportb(0x43,0xB6);
     outportb(0x42,count & 0xFF);
     outportb(0x42,count >> 8);
     outportb(0x61,bits | 0x03);
     while (biostime(0,0L) < begintime + ticks)
          ;    /* do nothing */
     outportb(0x61,bits);
}

void slidetone(int start, int finish, int inc)
{
     char bits;
     int count, hertz, j;

     bits = inportb(0x61);
     outportb(0x61,bits | 0x03);
     for (hertz = start; hertz != finish; hertz += inc) {
          count = 1193280 / hertz;
     /*   outportb(0x43,0xB6); */
          outportb(0x42,count & 0xFF);
          outportb(0x42,count >> 8);
          for (j = 0; j < 300; j++) ;
     }
     outportb(0x61,bits);
}
