1: #include "uucp.h"
   2: #include <sys/types.h>
   3: #include <sys/stat.h>
   4: 
   5: 
   6: struct Proto {
   7:     char P_id;
   8:     int (*P_turnon)();
   9:     int (*P_rdmsg)();
  10:     int (*P_wrmsg)();
  11:     int (*P_rddata)();
  12:     int (*P_wrdata)();
  13:     int (*P_turnoff)();
  14: };
  15: 
  16: 
  17: extern int gturnon(), gturnoff();
  18: extern int grdmsg(), grddata();
  19: extern int gwrmsg(), gwrdata();
  20: extern int imsg();
  21: extern int omsg();
  22: 
  23: struct Proto Ptbl[]={
  24:     'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff,
  25:     '\0'
  26: };
  27: 
  28: int (*Rdmsg)()=imsg, (*Rddata)();
  29: int (*Wrmsg)()=omsg, (*Wrdata)();
  30: int (*Turnon)(), (*Turnoff)();
  31: 
  32: 
  33: #define YES "Y"
  34: #define NO "N"
  35: #define Y 'Y'
  36: #define N 'N'
  37: 
  38: 
  39: #define XUUCP 'X'   /* execute uucp (string) */
  40: #define SLTPTCL 'P' /* select protocol  (string)  */
  41: #define USEPTCL 'U' /* use protocol (character) */
  42: #define RCVFILE 'R' /* receive file (string) */
  43: #define SNDFILE 'S' /* send file (string) */
  44: #define RQSTCMPT 'C'    /* request complete (string - yes | no) */
  45: #define HUP     'H' /* ready to hangup (string - yes | no) */
  46: 
  47: 
  48: #define W_TYPE      wrkvec[0]
  49: #define W_FILE1     wrkvec[1]
  50: #define W_FILE2     wrkvec[2]
  51: #define W_USER      wrkvec[3]
  52: #define W_OPTNS     wrkvec[4]
  53: #define W_DFILE     wrkvec[5]
  54: #define W_MODE      wrkvec[6]
  55: 
  56: #define RMESG(m, s) if (rmesg(m, s) != 0) return(FAIL);
  57: #define RAMESG(s) if (rmesg('\0', s) != 0) return(FAIL)
  58: #define WMESG(m, s) if(wmesg(m, s) != 0) return(FAIL)
  59: 
  60: char Wfile[MAXFULLNAME] = {'\0'};
  61: char Dfile[MAXFULLNAME];
  62: 
  63: /*******
  64:  *	cntrl(role, wkpre)
  65:  *	int role;
  66:  *	char *wkpre;
  67:  *
  68:  *	cntrl  -  this routine will execute the conversation
  69:  *	between the two machines after both programs are
  70:  *	running.
  71:  *
  72:  *	return codes
  73:  *		SUCCESS - ok
  74:  *		FAIL - failed
  75:  */
  76: 
  77: cntrl(role, wkpre)
  78: int role;
  79: char *wkpre;
  80: {
  81:     char msg[BUFSIZ], rqstr[BUFSIZ];
  82:     FILE *fp;
  83:     int filemode;
  84:     struct stat stbuf;
  85:     char filename[MAXFULLNAME], wrktype, *wrkvec[20];
  86:     extern (*Rdmsg)(), (*Wrmsg)();
  87:     extern char *index(), *lastpart();
  88:     int status = 1, i;
  89:     int ret;
  90:     static int pnum, tmpnum = 0;
  91: 
  92:     pnum = getpid();
  93: top:
  94:     DEBUG(4, "*** TOP ***  -  role=%d, ", role);
  95:     if (role == MASTER) {
  96:         /* get work */
  97:         if ((i = gtwvec(Wfile, Spool, wkpre, wrkvec)) == 0) {
  98:             WMESG(HUP, "");
  99:             RMESG(HUP, msg);
 100:             goto process;
 101:         }
 102:         wrktype = W_TYPE[0];
 103: 
 104:         DEBUG(4, "wrktype %c, ", wrktype);
 105:         if (wrktype == XUUCP) {
 106:             int n;
 107:             msg[0] = '\0';
 108:             for (n = 1; n < i; n++) {
 109:                 strcat(msg, " ");
 110:                 strcat(msg, wrkvec[n]);
 111:             }
 112:             sprintf(rqstr, "X %s", msg);
 113:             logent(rqstr, "REQUEST");
 114:             goto sendmsg;
 115:         }
 116: 
 117:         ASSERT(i > 4, "ARG COUNT - %d\n", i);
 118:         sprintf(msg, " %s %s %s %s %s %s",
 119:             W_FILE1, W_FILE2, W_USER,
 120:             W_OPTNS, W_DFILE, W_MODE);
 121:         strcpy(User, W_USER);
 122:         ASSERT(strlen(User) <= 10, "User - %s\n", User);
 123:         sprintf(rqstr, "%s %s %s %s", W_TYPE, W_FILE1,
 124:           W_FILE2, W_USER);
 125:         logent(rqstr, "REQUEST");
 126:         DEBUG(4, "User - %s\n", User);
 127:         if (wrktype == SNDFILE ) {
 128:             strcpy(filename, W_FILE1);
 129:             expfile(filename);
 130:             if (chkpth(User, "", filename)) {
 131:                 /*  access denied  */
 132:                 logent("DENIED", "ACCESS");
 133:                 unlink(W_DFILE);
 134:                 unlink(Wfile);
 135:                 goto top;
 136:             }
 137: 
 138:             strcpy(Dfile, W_DFILE);
 139:             if ((fp = fopen(Dfile, "r")) == NULL
 140:               && (fp = fopen(filename, "r")) == NULL) {
 141:                 /*  can not read data file  */
 142:                 logent("CAN'T READ DATA", "FAILED");
 143:                 unlink(Wfile);
 144:                 unlink(Dfile);
 145:                 goto top;
 146:             }
 147:         }
 148: 
 149:         if (wrktype == RCVFILE) {
 150:             strcpy(filename, W_FILE2);
 151:             expfile(filename);
 152:             if (chkpth(User, "", filename)
 153:              || chkperm(filename, User, index(W_OPTNS, 'd'))) {
 154:                 /*  access denied  */
 155:                 logent("DENIED", "ACCESS");
 156:                 unlink(Wfile);
 157:                 goto top;
 158:             }
 159:             sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
 160:             if ((fp = fopen(Dfile, "w")) == NULL) {
 161:                 /*  can not create temp  */
 162:                 logent("CAN'T CREATE TM", "FAILED");
 163:                 unlink(Wfile);
 164:                 unlink(Dfile);
 165:                 goto top;
 166:             }
 167:             chmod(Dfile, 0666);
 168:         }
 169: sendmsg:
 170:         DEBUG(4, "wrktype - %c, ", wrktype);
 171:         DEBUG(4, " fileno - %d\n", fileno(fp));
 172:         WMESG(wrktype, msg);
 173:         RMESG(wrktype, msg);
 174:         goto process;
 175:     }
 176: 
 177:     /* role is slave */
 178:     RAMESG(msg);
 179:     goto process;
 180: 
 181: process:
 182:     DEBUG(4, " PROCESS: msg - %s\n", msg);
 183:     switch (msg[0]) {
 184: 
 185:     case RQSTCMPT:
 186:         DEBUG(4, "%s\n", "RQSTCMPT:");
 187:         logent((msg[1] == 'N') ? "FAILED" : "SUCCEEDED", "REQUEST");
 188:         if (role == MASTER) {
 189:             notify(W_OPTNS, W_USER, W_FILE1, Rmtname,
 190:               (msg[1] == N) ? "failed" : "succeeded");
 191:         }
 192:         goto top;
 193: 
 194:     case HUP:
 195:         DEBUG(4, "%s\n", "HUP:");
 196:         if (msg[1] == Y) {
 197:             WMESG(HUP, YES);
 198:             (*Turnoff)();
 199:             Rdmsg = imsg;
 200:             Wrmsg = omsg;
 201:             return(0);
 202:         }
 203: 
 204:         if (msg[1] == N) {
 205:             ASSERT(role == MASTER,
 206:                 "role - %d", role);
 207:             role = SLAVE;
 208:             goto top;
 209:         }
 210: 
 211:         /* get work */
 212:         if (!iswrk(Wfile, "chk", Spool, wkpre)) {
 213:             WMESG(HUP, YES);
 214:             RMESG(HUP, msg);
 215:             goto process;
 216:         }
 217: 
 218:         WMESG(HUP, NO);
 219:         role = MASTER;
 220:         goto top;
 221: 
 222:     case XUUCP:
 223:         if (role == MASTER) {
 224:             unlink(Wfile);
 225:             goto top;
 226:         }
 227: 
 228:         /*  slave part  */
 229:         i = getargs(msg, wrkvec);
 230:         strcpy(filename, W_FILE1);
 231:         if (index(filename, ';') != NULL
 232:           || index(W_FILE2, ';') != NULL
 233:           || i < 3) {
 234:             WMESG(XUUCP, NO);
 235:             goto top;
 236:         }
 237:         expfile(filename);
 238:         if (chkpth("", Rmtname, filename)) {
 239:             WMESG(XUUCP, NO);
 240:             logent("XUUCP DENIED", filename);
 241:             goto top;
 242:         }
 243:         sprintf(rqstr, "%s %s", filename, W_FILE2);
 244:         xuucp(rqstr);
 245:         WMESG(XUUCP, YES);
 246:         goto top;
 247: 
 248:     case SNDFILE:
 249:         /*  MASTER section of SNDFILE  */
 250: 
 251:         DEBUG(4, "%s\n", "SNDFILE:");
 252:         if (msg[1] == N) {
 253:             logent("DENIED", "REQUEST");
 254:             ASSERT(role == MASTER,
 255:                 "role - %d", role);
 256:             fclose(fp);
 257:             unlink(W_DFILE);
 258:             unlink(Wfile);
 259:             goto top;
 260:         }
 261: 
 262:         if (msg[1] == Y) {
 263:             /* send file */
 264:             ASSERT(role == MASTER,
 265:                 "role - %d", role);
 266:             ret = (*Wrdata)(fp, Ofn);
 267:             fclose(fp);
 268:             if (ret != 0)
 269:                 return(FAIL);
 270:             unlink(W_DFILE);
 271:             RMESG(RQSTCMPT, msg);
 272:             goto process;
 273:         }
 274: 
 275:         /*  SLAVE section of SNDFILE  */
 276:         ASSERT(role == SLAVE,
 277:             "role - %d", role);
 278: 
 279:         /* request to receive file */
 280:         /* check permissions */
 281:         i = getargs(msg, wrkvec);
 282:         ASSERT(i > 4, "ARG COUNT - %d\n", i);
 283:         sprintf(rqstr, "%s %s %s %s", W_TYPE, W_FILE1,
 284:           W_FILE2, W_USER);
 285:         logent(rqstr, "REQUESTED");
 286:         DEBUG(4, "msg - %s\n", msg);
 287:         DEBUG(4, "W_FILE2 - %s\n", W_FILE2);
 288:         strcpy(filename, W_FILE2);
 289:         expfile(filename);
 290:         if (chkpth("", Rmtname, filename)
 291:          || chkperm(filename, Loginuser, index(W_OPTNS, 'd'))) {
 292:             WMESG(SNDFILE, NO);
 293:             logent("DENIED", "PERMISSION");
 294:             goto top;
 295:         }
 296:         if (isdir(filename)) {
 297:             strcat(filename, "/");
 298:             strcat(filename, lastpart(W_FILE1));
 299:         }
 300:         strcpy(User, W_USER);
 301:         ASSERT(strlen(User) <= 10, "User - %s\n", User);
 302: 
 303:         DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
 304:         sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
 305:         if((fp = fopen(Dfile, "w")) == NULL) {
 306:             WMESG(SNDFILE, NO);
 307:             logent("CAN'T OPEN", "DENIED");
 308:             unlink(Dfile);
 309:             goto top;
 310:         }
 311:         chmod(Dfile, 0666);
 312: 
 313:         WMESG(SNDFILE, YES);
 314:         ret = (*Rddata)(Ifn, fp);
 315:         fclose(fp);
 316:         if (ret != 0)
 317:             return(FAIL);
 318:         /* copy to user directory */
 319:         status = xmv(Dfile, filename);
 320:         WMESG(RQSTCMPT, status ? NO : YES);
 321:         logent(status ? "FAILED" : "SUCCEEDED", "COPY");
 322:         sscanf(W_MODE, "%o", &filemode);
 323:         DEBUG(4, "mode - %o\n", filemode);
 324:         if (filemode <= 0)
 325:             filemode = 0666;
 326:         if (status == 0) {
 327:             filemode |= 0666;
 328:             chmod(filename, filemode | 0666);
 329:         }
 330:         goto top;
 331: 
 332:     case RCVFILE:
 333:         /*  MASTER section of RCVFILE  */
 334: 
 335:         DEBUG(4, "%s\n", "RCVFILE:");
 336:         if (msg[1] == N) {
 337:             logent("REQUEST", "DENIED");
 338:             ASSERT(role == MASTER,
 339:                 "role - %d", role);
 340:             unlink(Wfile);
 341:             fclose(fp);
 342:             goto top;
 343:         }
 344: 
 345:         if (msg[1] == Y) {
 346:             /* receive file */
 347:             ASSERT(role == MASTER,
 348:                 "role - %d", role);
 349:             ret = (*Rddata)(Ifn, fp);
 350:             fclose(fp);
 351:             if (ret != 0)
 352:                 return(FAIL);
 353:             /* copy to user directory */
 354:             if (isdir(filename)) {
 355:                 strcat(filename, "/");
 356:                 strcat(filename, lastpart(W_FILE1));
 357:             }
 358:             status = xmv(Dfile, filename);
 359:             WMESG(RQSTCMPT, status ? NO : YES);
 360:             logent(status ? "FAILED" : "SUCCEEDED", "COPY");
 361:             notify(W_OPTNS, W_USER, filename, Rmtname,
 362:               status ? "failed" : "succeeded");
 363:             sscanf(&msg[2], "%o", &filemode);
 364:             DEBUG(4, "mode - %o\n", filemode);
 365:             if (filemode <= 0)
 366:                 filemode = 0666;
 367:             if (status == 0) {
 368:                 unlink(Dfile);
 369:                 filemode |= 0666;
 370:                 chmod(filename, filemode | 0666);
 371:             }
 372:             goto top;
 373:         }
 374: 
 375:         /*  SLAVE section of RCVFILE  */
 376:         ASSERT(role == SLAVE,
 377:             "role - %d", role);
 378: 
 379:         /* request to send file */
 380:         strcpy(rqstr, msg);
 381:         logent(rqstr, "REQUESTED");
 382: 
 383:         /* check permissions */
 384:         i = getargs(msg, wrkvec);
 385:         ASSERT(i > 3, "ARG COUNT - %d\n", i);
 386:         DEBUG(4, "msg - %s\n", msg);
 387:         DEBUG(4, "W_FILE1 - %s\n", W_FILE1);
 388:         strcpy(filename, W_FILE1);
 389:         expfile(filename);
 390:         if (isdir(filename)) {
 391:             strcat(filename, "/");
 392:             strcat(filename, lastpart(W_FILE2));
 393:         }
 394:         strcpy(User, W_USER);
 395:         ASSERT(strlen(User) <= 10, "User - %s\n", User);
 396:         if (chkpth("", Rmtname, filename) != 0) {
 397:             WMESG(RCVFILE, NO);
 398:             logent("DENIED", "PERMISSION");
 399:             goto top;
 400:         }
 401:         DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
 402: 
 403:         if ((fp = fopen(filename, "r")) == NULL) {
 404:             WMESG(RCVFILE, NO);
 405:             logent("CAN'T OPEN", "DENIED");
 406:             goto top;
 407:         }
 408: 
 409:         /*  ok to send file */
 410:         ret = stat(filename, &stbuf);
 411:         ASSERT(ret != -1, "STAT FAILED %s", filename);
 412:         sprintf(msg, "%s %o", YES, stbuf.st_mode & 0777);
 413:         WMESG(RCVFILE, msg);
 414:         ret = (*Wrdata)(fp, Ofn);
 415:         fclose(fp);
 416:         if (ret != 0)
 417:             return(FAIL);
 418:         RMESG(RQSTCMPT, msg);
 419:         goto process;
 420:     }
 421:     return(FAIL);
 422: }
 423: 
 424: 
 425: /***
 426:  *	rmesg(c, msg)	read message 'c'
 427:  *	char *msg, c;
 428:  *
 429:  *	return code:  0  |  FAIL
 430:  */
 431: 
 432: rmesg(c, msg)
 433: char *msg, c;
 434: {
 435:     char str[50];
 436: 
 437:     DEBUG(4, "rmesg - '%c' ", c);
 438:     if ((*Rdmsg)(msg, Ifn) != 0) {
 439:         DEBUG(4, "got %s\n", "FAIL");
 440:         sprintf(str, "expected '%c' got FAIL", c);
 441:         logent(str, "BAD READ");
 442:         return(FAIL);
 443:     }
 444:     if (c != '\0' && msg[0] != c) {
 445:         DEBUG(4, "got %s\n", msg);
 446:         sprintf(str, "expected '%c' got %.25s", c, msg);
 447:         logent(str, "BAD READ");
 448:         return(FAIL);
 449:     }
 450:     DEBUG(4, "got %.25s\n", msg);
 451:     return(0);
 452: }
 453: 
 454: 
 455: /***
 456:  *	wmesg(m, s)	write a message (type m)
 457:  *	char *s, m;
 458:  *
 459:  *	return codes: 0 - ok | FAIL - ng
 460:  */
 461: 
 462: wmesg(m, s)
 463: char *s, m;
 464: {
 465:     DEBUG(4, "wmesg '%c'", m);
 466:     DEBUG(4, "%.25s\n", s);
 467:     return((*Wrmsg)(m, s, Ofn));
 468: }
 469: 
 470: 
 471: /***
 472:  *	notify(options, user, file, sys, stwork)	mail results of copy
 473:  *	char *options, *user, *file, *sys, *stword);
 474:  *
 475:  *	return codes:  none
 476:  */
 477: 
 478: notify(options, user, file, sys, stword)
 479: char *options, *user, *file, *sys, *stword;
 480: {
 481:     char str[200];
 482:     if (index(options, 'm') == NULL)
 483:         return;
 484:     sprintf(str, "file %s, system %s, copy %s\n", file, sys, stword);
 485:     mailst(user, str);
 486:     return;
 487: }
 488: 
 489: 
 490: /***
 491:  *	startup(role)
 492:  *	int role;
 493:  *
 494:  *	startup  -  this routine will converse with the remote
 495:  *	machine, agree upon a protocol (if possible) and start the
 496:  *	protocol.
 497:  *
 498:  *	return codes:
 499:  *		SUCCESS - successful protocol selection
 500:  *		FAIL - can't find common or open failed
 501:  */
 502: 
 503: startup(role)
 504: int role;
 505: {
 506:     extern (*Rdmsg)(), (*Wrmsg)();
 507:     extern imsg(), omsg();
 508:     extern char *blptcl(), fptcl();
 509:     char msg[BUFSIZ], str[BUFSIZ];
 510: 
 511:     Rdmsg = imsg;
 512:     Wrmsg = omsg;
 513:     if (role == MASTER) {
 514:         RMESG(SLTPTCL, msg);
 515:         if ((str[0] = fptcl(&msg[1])) == NULL) {
 516:             /* no protocol match */
 517:             WMESG(USEPTCL, NO);
 518:             return(FAIL);
 519:         }
 520:         str[1] = '\0';
 521:         WMESG(USEPTCL, str);
 522:         if (stptcl(str) != 0)
 523:             return(FAIL);
 524:         DEBUG(4, "protocol %s\n", str);
 525:         return(SUCCESS);
 526:     }
 527:     else {
 528:         WMESG(SLTPTCL, blptcl(str));
 529:         RMESG(USEPTCL, msg);
 530:         if (msg[1] == N) {
 531:             return(FAIL);
 532:         }
 533: 
 534:         if (stptcl(&msg[1]) != 0)
 535:             return(FAIL);
 536:         DEBUG(4, "Protocol %s\n", msg);
 537:         return(SUCCESS);
 538:     }
 539: }
 540: 
 541: 
 542: /*******
 543:  *	char
 544:  *	fptcl(str)
 545:  *	char *str;
 546:  *
 547:  *	fptcl  -  this routine will choose a protocol from
 548:  *	the input string (str) and return the found letter.
 549:  *
 550:  *	return codes:
 551:  *		'\0'  -  no acceptable protocol
 552:  *		any character  -  the chosen protocol
 553:  */
 554: 
 555: char
 556: fptcl(str)
 557: char *str;
 558: {
 559:     struct Proto *p;
 560:     extern char *index();
 561: 
 562:     for (p = Ptbl; p->P_id != '\0'; p++) {
 563:         if (index(str, p->P_id) != NULL) {
 564:             return(p->P_id);
 565:         }
 566:     }
 567: 
 568:     return('\0');
 569: }
 570: 
 571: 
 572: /***
 573:  *	char *
 574:  *	blptcl(str)
 575:  *	char *str;
 576:  *
 577:  *	blptcl  -  this will build a string of the
 578:  *	letters of the available protocols and return
 579:  *	the string (str).
 580:  *
 581:  *	return:
 582:  *		a pointer to string (str)
 583:  */
 584: 
 585: char *
 586: blptcl(str)
 587: char *str;
 588: {
 589:     struct Proto *p;
 590:     char *s;
 591: 
 592:     for (p = Ptbl, s = str; (*s++ = p->P_id) != '\0'; p++);
 593:     return(str);
 594: }
 595: 
 596: /***
 597:  *	stptcl(c)
 598:  *	char *c;
 599:  *
 600:  *	stptcl  -  this routine will set up the six routines
 601:  *	(Rdmsg, Wrmsg, Rddata, Wrdata, Turnon, Turnoff) for the
 602:  *	desired protocol.
 603:  *
 604:  *	return codes:
 605:  *		SUCCESS - ok
 606:  *		FAIL - no find or failed to open
 607:  *
 608:  */
 609: 
 610: stptcl(c)
 611: char *c;
 612: {
 613:     struct Proto *p;
 614: 
 615:     for (p = Ptbl; p->P_id != '\0'; p++) {
 616:         if (*c == p->P_id) {
 617:             /* found protocol - set routines */
 618:             Rdmsg = p->P_rdmsg;
 619:             Wrmsg = p->P_wrmsg;
 620:             Rddata = p->P_rddata;
 621:             Wrdata = p->P_wrdata;
 622:             Turnon = p->P_turnon;
 623:             Turnoff = p->P_turnoff;
 624:             if ((*Turnon)() != 0)
 625:                 return(FAIL);
 626:             DEBUG(4, "Proto started %c\n", *c);
 627:             return(SUCCESS);
 628:         }
 629:     }
 630:     DEBUG(4, "Proto start-fail %c\n", *c);
 631:     return(FAIL);
 632: }

Defined functions

blptcl defined in line 585; used 2 times
cntrl defined in line 77; used 1 times
fptcl defined in line 555; used 2 times
notify defined in line 478; used 2 times
rmesg defined in line 432; used 2 times
startup defined in line 503; used 1 times
stptcl defined in line 610; used 2 times
wmesg defined in line 462; used 1 times
  • in line 58

Defined variables

Dfile defined in line 61; used 14 times
Ptbl defined in line 23; used 3 times
Wfile defined in line 60; used 9 times

Defined struct's

Proto defined in line 6; used 8 times

Defined macros

HUP defined in line 45; used 6 times
N defined in line 36; used 5 times
NO defined in line 34; used 10 times
RAMESG defined in line 57; used 1 times
RCVFILE defined in line 42; used 4 times
RMESG defined in line 56; used 7 times
RQSTCMPT defined in line 44; used 4 times
SLTPTCL defined in line 40; used 2 times
SNDFILE defined in line 43; used 4 times
USEPTCL defined in line 41; used 3 times
WMESG defined in line 58; used 19 times
W_DFILE defined in line 53; used 5 times
W_FILE1 defined in line 49; used 10 times
W_FILE2 defined in line 50; used 9 times
W_MODE defined in line 54; used 2 times
W_OPTNS defined in line 52; used 5 times
W_TYPE defined in line 48; used 3 times
W_USER defined in line 51; used 8 times
XUUCP defined in line 39; used 4 times
Y defined in line 35; used 3 times
YES defined in line 33; used 7 times
Last modified: 1979-01-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1432
Valid CSS Valid XHTML 1.0 Strict