Path: wuarchive!wugate!wupost!uunet!mcvax!hp4nl!dutrun!duteca4!marcel From: marcel@duteca (Marcel Mol) Newsgroups: comp.binaries.apple2 Subject: SCIIBIN: a binscii extracter in C Message-ID: <516@duteca4.UUCP> Date: 16 May 89 19:02:28 GMT Reply-To: marcel@duteca.UUCP (Marcel J.E. Mol) Organization: Delft University of Technology, Dep. of Electrotechnical engineering. Lines: 681 Here is a C program that views and extracts BINSCII files. When viewing, it shows file names and attributes and which part of how many parts the BINSCII file is. It handles multiple file names on the command line, and each file may contain several BINSCII files, so you can directely feed the news articles to the program. - Marcel =========== CUT HERE ==================================== /* @(#) sciibin.c 1.0 03/03/89 */ /************************************************************************* ** ** ** Name : sciibin ** ** Author : Marcel J.E. Mol ** ** Date : 06/03/89 (first release) ** ** Version : 1.00 ** ** Files : sciibin.c Main source file ** ** ** ** ------------------------- Revision List ------------------------- ** ** Ver Date Name Remarks ** ** 1.00 06/03/89 Marcel Mol First release ** ** 1.10 27/03/89 Marcel Mol Fished things up, error ** ** routine, linecount, ** ** all info fields filled in, ** ** changed info layout. ** ** ================================================================= ** ** ** ** Compile as follows: cc cc sciibin.c -Oso sciibin ** ** ** ** Usage: sciibin [-hvtc] [-o] ** ** ** ** -v show only info on file, do not create output. ** ** -t test file, do not create output. ** ** -c do not check checksums. ** ** -o create given filename instead of the one in ** ** binscii file. Use this only if the input files ** ** contain only one output file. ** ** -h help. ** ** ** ** ** ** Defining DEBUG gives some debug information. ** ** Defining DEBUGALL gives input and output of the decode ** ** routine. ** ** ** ** This software is freeware. I can not be held responsible to ** ** any damage this program may coase you or anyone or anything else. ** ** ** ************************************************************************/ #include #include #define BUFLEN 256 /* * Global variables */ char buf[BUFLEN+1]; unsigned char dec[BUFLEN+1]; char alfabet[BUFLEN+1]; char outfilename[BUFLEN+1]; int outflag = 0; /* the -o option */ int crcflag = 0; /* the -c option */ int infoflag = 0; /* the -v option */ int testflag = 0; /* the -t option */ int makeoutput; /* ! (-t | -v) */ int crcok; /* -t | -c */ FILE *outfp; /* output file */ int namlen, filetype, numblocks; long filesize, startbyte, segmentlen; int modyear, modmonth, modday, modhour, modmin; int creyear, cremonth, creday, crehour, cremin; int auxtype, stortype, access; char * infilename; int linecount; char * progname; /* * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. * NOTE: First srgument must be in range 0 to 255. * Second argument is referenced twice. * * Programmers may incorporate any or all code into their programs, * giving proper credit within the source. Publication of the * source routines is permitted so long as proper credit is given * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, * Omen Technology. */ /* #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) */ #define updcrc(cp, crc) ( (crctab[((crc >> 8) & 0xFF) ^ cp] ^ (crc << 8)) & 0xFFFF) /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ static unsigned short crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; char * filetypes[] = { "$00", "bad", "pcd", "ptx", "txt", "pda", "bin", "fnt", "fot", "ba3", "da3", "wpf", "sos", "$0D", "$0E", "dir", "rpd", "rpi", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "adb", "awp", "asp", "$1C", "$1D", "$1E", "$1F", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$2A", "$2B", "$2C", "$2D", "$2E", "$2F", "$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", "$3A", "$3B", "$3C", "$3D", "$3E", "$3F", "$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47", "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", "$50", "$51", "$52", "$53", "$54", "$55", "$56", "$57", "$58", "$59", "$5A", "$5B", "$5C", "$5D", "$5E", "$5F", "$60", "$61", "$62", "$63", "$64", "$65", "$66", "$67", "$68", "$69", "$6A", "$6B", "$6C", "$6D", "$6E", "$6F", "$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F", "$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87", "$88", "$89", "$8A", "$8B", "$8C", "$8D", "$8E", "$8F", "$90", "$91", "$92", "$93", "$94", "$95", "$96", "$97", "$98", "$99", "$9A", "$9B", "$9C", "$9D", "$9E", "$9F", "$A0", "$A1", "$A2", "$A3", "$A4", "$A5", "$A6", "$A7", "$A8", "$A9", "$AA", "$AB", "$AC", "$AD", "$AE", "$AF", "src", "obj", "lib", "s16", "rtl", "exe", "str", "tsf", "nda", "cda", "tol", "drv", "$BC", "$BD", "$BE", "doc", "pnt", "pic", "$C2", "$C3", "$C4", "$C5", "$C6", "$C7", "fon", "$C9", "$CA", "$CB", "$CC", "$CD", "$CE", "$CF", "$D0", "$D1", "$D2", "$D3", "$D4", "$D5", "$D6", "$D7", "$D8", "$D9", "$DA", "$DB", "$DC", "$DD", "$DE", "$DF", "$E0", "$E1", "$E2", "$E3", "$E4", "$E5", "$E6", "$E7", "$E8", "$E9", "$EA", "$EB", "$EC", "$ED", "$EE", "pas", "cmd", "$F1", "$F2", "$F3", "$F4", "$F5", "$F6", "$F7", "$F8", "p16", "int", "ivr", "bas", "var", "rel", "sys", }; /* ProDOS Filetypes Num Name OS Meaning ======================================================================== $00 typeless $01 BAD both BAD blocks file $02 PCD SOS Pascal CoDe file $03 PTX SOS Pascal TeXt file $04 TXT both ASCII text file $05 PDA SOS Pascal DAta file $06 BIN both BINary file $07 CHR SOS CHaRacter font file $08 PIC both PICture file $09 BA3 SOS Business BASIC (SOS) program file $0A DA3 SOS Business BASIC (SOS) data file $0B WPD SOS Word Processor Document $0C SOS SOS system file $0D SOS SOS reserved file type $0E SOS SOS reserved file type $0F DIR Both subDIRectory file $10 RPD SOS RPS data file $11 RPI SOS RPS index file $12 SOS Applefile diskcard file $13 SOS Applefile model file $14 SOS Applefile report format file $15 SOS Screen library file $16 SOS SOS reserved file type $17 SOS SOS reserved file type $18 SOS SOS reserved file type $19 ADB ProDOS AppleWorks Database file $1A AWP ProDOS AppleWorks WordProcessing file $1B ASP ProDOS AppleWorks Spreadsheet file $1C-$5F Reserved $60-$6F ProDOS PC Transporter (Applied Engineering) reserved filetypes $60 PRE ProDOS ProDOS preboot driver $61-$6A ProDOS Reserved $6B NIO ProDOS PC Transporter BIOS and drivers $6C ProDOS Reserved $6D DVR ProDOS PC Transporter device drivers $6E ProDOS Reserved $6F HDV ProDOS MSDOS HardDisk Volume $70-$9F Reserved $A0 WPF ProDOS WordPerfect document file $A1 MAC ProDOS Macrofile $A2 HLP ProDOS Help File $A3 DAT ProDOS Data File $A4 Reserved $A5 LEX ProDOS Spelling dictionary $A6-$AB Reserved $AC ARC ProDOS General Purpose Archive file $AD-$AF Reserved $B0 SRC ProDOS ORCA/M & APW source file $B1 OBJ ProDOS ORCA/M & APW object file $B2 LIB ProDOS ORCA/M & APW library file $B3 S16 ProDOS ProDOS16 system file $B4 RTL ProDOS ProDOS16 runtime library $B5 EXE ProDOS APW shell command file $B6 STR ProDOS ProDOS16 startup init file $B7 TSF ProDOS ProDOS16 temporary init file $B8 NDA ProDOS ProDOS16 new desk accessory $B9 CDA ProDOS ProDOS16 classic desk accessory $BA TOL ProDOS ProDOS16 toolset file $BB DRV ProDOS ProDOS16 driver file $BC-$BE Reserved for ProDOS16 load file $BF DOC ProDOS document file $C0 PNT ProDOS //gs paint document $C1 SCR ProDOS //gs screen file $C2-$C7 Reserved $C8 FNT ProDOS Printer font file $C9 ProDOS finder files $CA ProDOS finder icons $CB-$DF Reserved $E0 LBR ProDOS Apple archive library file $E1 Unknown (unlisted) $E2 ATI ProDOS Appletalk init file $E3-$EE Reserved $EF PAS ProDOS ProDOS Pascal file $F0 CMD ProDOS added command file $F1-$F8 ProDOS User defined filetypes (popular ones include:) $F1 OVL ProDOS Overlay file $F2 DBF ProDOS Database file $F3 PAD ProDOS MouseWrite file $F4 MCR ProDOS AE Pro macro file $F5 ECP ProDOS ECP batch file $F6 DSC ProDOS description file $F7 TMP ProDOS temporary work file $F8 RSX ProDOS linkable object module $F9 IMG ProDOS ProDOS image file $FA INT ProDOS Integer BASIC program $FB IVR ProDOS Integer BASIC variables file $FC BAS ProDOS AppleSoft BASIC program $FD VAR ProDOS AppleSoft BASIC variables file $FE REL ProDOS ProDOS EDASM relocatable object module file $FF SYS ProDOS ProDOS8 system file */ /* * function declarations */ sciibin(); getheader(); decode(); decodestring(); char *myfgets(); void usage(); void error(); char * copyright = "@(#) sciibin.c 1.1 27/03/89 (c) M.J.E. Mol"; main(argc, argv) int argc; char **argv; { FILE *fp; int c; extern int optind; /* For getopt */ extern char * optarg; /* For getopt */ int flag; /* Flag for getopt */ progname = *argv; while ((flag = getopt(argc, argv, "hvcto:")) != EOF) { /* Process options */ switch (flag) { case 'v': infoflag = 1; /* Want only info of file */ break; case 'h': usage(); /* Give help */ exit(0); case 'c': crcflag = 1; break; case 't': testflag = 1; break; case 'o': strcpy(outfilename, optarg); outflag = 1; break; default : fprintf(stderr, "%s: skipping unkown flag %c, use -h.\n", progname, flag); break; } } makeoutput = !(testflag | infoflag); crcok = testflag | crcflag; #if defined(DEBUG) fprintf(stderr, "make output: %d, crcok: %d\n", makeoutput, crcok); #endif if (optind >= argc) { /* No files given, use stdin */ infilename = "stdin"; linecount = 0; sciibin(stdin); } else while (optind < argc) { infilename = argv[optind]; optind++; if ((fp = fopen(infilename, "r")) == NULL) { perror(infilename); continue; } linecount = 0; sciibin(fp); fclose(fp); } exit(0); } /* main */ /* * Walk over the file processing all segments in it */ sciibin(fp) FILE *fp; { int processed = 0; /* number of processed binscii segments */ int status = 0; /* return codes of calls to decode */ while (myfgets(buf, BUFLEN, fp) != NULL) { #if defined(DEBUG) fprintf(stderr, "(%s) get start:%s", infilename, buf); #endif if (!strcmp(buf, "FiLeStArTfIlEsTaRt\n")) { if (!getheader(fp) && !infoflag) /* if header ok and not -v flag */ status |= decode(fp); processed++; } } if (processed == 0) { error("not a binscii file"); return 1; } return status; } /* sciibin */ /* * Build the alfabet, get the output file info and open output file * if necessary. * Still contains lots of debug code to find out the header structure. * (every bit is known now...) */ getheader(fp) FILE *fp; { register int i, j; register int crc = 0; struct stat statbuf; /* must know if file exists */ char *iomod; /* write or readwrite a file */ /* * Get the alfabet */ if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading alfabet: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) alfabet:%s", infilename, buf); #endif if (strlen(buf) != 65) { error("alfabet corrupted"); return 1; } /* * Process the alfabet */ for (i = 0; i < BUFLEN; i++) alfabet[i] = 0xff; for (i = 0; i < 64; i++) { j = buf[i]; if (alfabet[j] != 0xff) error("Warning: double character in alfabet"); alfabet[j] = i; } #if defined(DEBUG) for (i = 0; i < BUFLEN; i+=16) { fprintf(stderr, "(%s) alfabet[%3d] =", infilename, i); for (j = 0; j < 16; j++) fprintf(stderr, " %02X", alfabet[i+j]); putc('\n', stderr); } #endif /* * Get the file header */ if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading fileheader: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) fileheader:%s", infilename, buf); #endif /* * Strip output filename if needed */ if (!outflag) { namlen = *buf - 'A' + 1; /* IS +1 NEEDED ?? */ strncpy(outfilename, buf+1, namlen); } #if defined(DEBUG) fprintf(stderr, "(%s) filename:**%s**\n", infilename, outfilename); fprintf(stderr, "(%s) fileinfo:**%s**", infilename, buf+16); #endif /* * Decode and process the file header information */ if ((i = decodestring(buf+16, dec)) != 27) error("warning: corrupted file header length"); for (i = 0; i < 24; i++) crc = updcrc(dec[i], crc); if (crc != (dec[24] | (dec[25] << 8))) { if (crcok) error("warning: CRC error in file header"); else { error("error: CRC error in file header"); return 1; } } filesize = dec[0] + (dec[1]<<8) + (dec[2]<<16);/* Calculate file length */ startbyte = dec[3] + (dec[4]<<8) + (dec[5]<<16); access = dec[6]; filetype = dec[7]; auxtype = dec[8] + (dec[9] << 8); stortype = dec[10]; numblocks = dec[11] + (dec[12]<<8); #define CRE 13 /* perhaps creation and modification date are swapped */ creday = dec[CRE] & 0x1f; cremonth = ((dec[CRE+1] & 0x01) << 3) | (dec[CRE] >> 5); creyear = dec[CRE+1] >>1; cremin = dec[CRE+2] & 0x3f; crehour = dec[CRE+3] & 0x1f; #define MOD CRE+4 modday = dec[MOD] & 0x1f; modmonth = ((dec[MOD+1] & 0x01) << 3) | (dec[MOD] >> 5); modyear = dec[MOD+1] >>1; modmin = dec[MOD+2] & 0x3f; modhour = dec[MOD+3] & 0x1f; segmentlen = dec[21] + (dec[22]<<8) + (dec[23]<<16); #define READ 0x01 #define WRITE 0x02 #define BACKUP 0x20 #define RENAME 0x40 #define DESTROY 0x80 if (infoflag) { printf("%-15s %3s aux: %04X ", outfilename, filetypes[filetype], auxtype); putchar(access & READ ? 'r' : '-'); putchar(access & WRITE ? 'w' : '-'); putchar(access & RENAME ? 'n' : '-'); putchar(access & DESTROY ? 'd' : '-'); putchar(access & BACKUP ? 'b' : '-'); switch (stortype) { case 0x0F : printf(" voldir"); break; case 0x0D : printf(" dir"); break; case 0x01 : printf(" seed"); break; case 0x02 : printf(" sap"); break; case 0x03 : printf(" tree"); break; default : printf(" ???"); break; } printf(" %02d/%02d/%02d(%02d:%02d) -", modyear, modmonth, modday, modhour, modmin); printf(" %02d/%02d/%02d(%02d:%02d)\n", creyear, cremonth, creday, crehour, cremin); printf("Part %4d of %4d,", startbyte / 0x3000 + 1, (filesize + 0x2FFF) / 0x3000); printf(" bytes %7d to %7d of %7d bytes, %5d blocks\n", startbyte, startbyte+segmentlen, filesize, numblocks); } if (makeoutput) { iomod = (stat(outfilename, &statbuf) == 0) ? "r+" : "w"; if ((outfp = fopen(outfilename, iomod)) == NULL) { error("unable to open output file"); perror(outfilename); return 1; } fseek(outfp, startbyte, 0); } return 0; } /* getheader */ /* * Do the actual decoding of the bin data. */ decode(fp) FILE *fp; { register int i; register int crc = 0; int len; crc = 0; while (segmentlen > 0) { if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading file: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) data:%s", infilename, buf); #endif if ((len = decodestring(buf, dec)) != 48) error("warning: corrupted line length"); for (i = 0; i < 48; i++) crc = updcrc(dec[i], crc); if (makeoutput) for (i = 0; (i < len) && (segmentlen > 0); i++, segmentlen--) putc(dec[i], outfp); /* COULD CR/NL TXT FILES */ else segmentlen -= len; #if defined(DEBUG) fprintf(stderr, "(%s) still need %d bytes\n", infilename, segmentlen); #endif } /* * must be at end of segment now, with one remaining line containing * the crc check. */ if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading file crc: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) crc:%s", infilename, buf); #endif if ((len = decodestring(buf, dec)) != 3) error("warning: corrupted crc length"); if (crc != (dec[0] | (dec[1] << 8))) { if (crcok) error("warning: CRC error in file data"); else { error("error: CRC error in file data"); return 1; } } fclose(outfp); return 0; } /* decode */ /* * Decode one string off scii characters to binary data, meanwhile * calculating crc. */ decodestring(in, out) register char *in; register unsigned char *out; { register int len = 0; #if defined(DEBUGALL) char *b; fprintf(stderr, "(%s) decode in: %s\n", infilename, in); b = in; while (*b) fprintf(stderr, ".%02X", alfabet[*b++]); putc('\n', stderr); b = out; #endif while (strlen(in) > 3) { *out++ = ((alfabet[in[3]] << 2) | (alfabet[in[2]] >> 4)) & 0xFF; *out++ = ((alfabet[in[2]] << 4) | (alfabet[in[1]] >> 2)) & 0xFF; *out++ = ((alfabet[in[1]] << 6) | (alfabet[in[0]])) & 0xFF; len += 3; in += 4; } *out = '\0'; if (*in != '\0' && *in != '\n') error("warning: line not ended by NULL or NEWLINE"); #if defined(DEBUGALL) fprintf(stderr, "(%s) decode out:\n", infilename); while (b != out) fprintf(stderr, ".%02X", *b++); putc('\n', stderr); #endif return len; } /* decodestring */ char *myfgets(buf, len, fp) char *buf; int len; FILE *fp; { linecount++; return fgets(buf, len, fp); } /* myfgets */ void usage() { fprintf(stderr, "Usage: sciibin [-vtc] [-o] \n\n"); fprintf(stderr, " -v show only info on file, do not create output.\n"); fprintf(stderr, " -t test file, do not create output.\n"); fprintf(stderr, " -c do not check checksums.\n"); fprintf(stderr, " -o create given filename instead of the one in\n"); fprintf(stderr, " binscii file. Use this only if the input files\n"); fprintf(stderr, " contain only one output file.\n"); fprintf(stderr, " -h this help message.\n"); } /* usage */ void error(str) char *str; { fprintf(stderr, "%s (%s, %d): %s\n", progname, infilename, linecount, str); } /* error */ -- ######################################### # Marcel J.E. Mol # They hate you if your're clever # Delft, University of Technology # And they despise the fool # The Netherlands # Till you're so fucking crazy # UUCP: marcel@duteca.UUCP # You can't follow the rules. # duteca!marcel # ######################################### - Lennon