Annotation of researchv10no/ipc/servers/ftpcmd.y, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Grammar for FTP commands.
                      3:  * See RFC 765.
                      4:  */
                      5: 
                      6: %{
                      7: 
                      8: #ifndef lint
                      9: static char sccsid[] = "@(#)ftpcmd.y   4.11 83/06/22";
                     10: #endif
                     11: 
                     12: #include <sys/types.h>
                     13: 
                     14: #include <sys/inet/in.h>
                     15: 
                     16: #include "ftp.h"
                     17: 
                     18: #include <stdio.h>
                     19: #include <signal.h>
                     20: #include <ctype.h>
                     21: #include <pwd.h>
                     22: #include <setjmp.h>
                     23: 
                     24: struct socket {
                     25:        unsigned short sport;
                     26:        long saddr;
                     27: };
                     28: char dest[128];
                     29: extern int logged_in;
                     30: extern struct passwd *pw;
                     31: extern int logging;
                     32: extern int type;
                     33: extern int form;
                     34: extern int debug;
                     35: extern int timeout;
                     36: extern char hostname[];
                     37: extern char *globerr;
                     38: extern int usedefault;
                     39: extern int pasv;
                     40: char   **glob();
                     41: 
                     42: static int cmd_type;
                     43: static int cmd_form;
                     44: static int cmd_bytesz;
                     45: 
                     46: char   *strchr();
                     47: %}
                     48: 
                     49: %token
                     50:        A       B       C       E       F       I
                     51:        L       N       P       R       S       T
                     52: 
                     53:        SP      CRLF    COMMA   STRING  NUMBER
                     54: 
                     55:        USER    PASS    ACCT    REIN    QUIT    PORT
                     56:        PASV    TYPE    STRU    MODE    RETR    STOR
                     57:        APPE    MLFL    MAIL    MSND    MSOM    MSAM
                     58:        MRSQ    MRCP    ALLO    REST    RNFR    RNTO
                     59:        ABOR    DELE    CWD     LIST    NLST    SITE
                     60:        STAT    HELP    NOOP    XMKD    XRMD    XPWD
                     61:        XCUP    OPEN    CLOS    READ    WRIT    SEEK
                     62: 
                     63:        LEXERR
                     64: 
                     65: %start cmd_list
                     66: 
                     67: %%
                     68: 
                     69: cmd_list:      /* empty */
                     70:        |       cmd_list cmd
                     71:        ;
                     72: 
                     73: cmd:           USER SP username CRLF
                     74:                = {
                     75:                        extern struct passwd *getpwnam();
                     76: 
                     77:                        pw = getpwnam($3);
                     78:                        reply(331, "Password required for %s.", $3);
                     79:                        if (pw->pw_uid==0)
                     80:                                pw = NULL;
                     81:                        if (pw == NULL)
                     82:                                reply(530, "User %s unknown.", $3);
                     83:                        free($3);
                     84:                }
                     85:        |       PASS SP password CRLF
                     86:                = {
                     87:                        pass($3);
                     88:                        free($3);
                     89:                }
                     90:        |       PORT SP host_port CRLF
                     91:                = {
                     92:                        usedefault = 0;
                     93:                        ack($1);
                     94:                }
                     95:        |       TYPE SP type_code CRLF
                     96:                = {
                     97:                        switch (cmd_type) {
                     98: 
                     99:                        case TYPE_A:
                    100:                                if (cmd_form == FORM_N) {
                    101:                                        reply(200, "Type set to A.");
                    102:                                        type = cmd_type;
                    103:                                        form = cmd_form;
                    104:                                } else
                    105:                                        reply(504, "Form must be N.");
                    106:                                break;
                    107: 
                    108:                        case TYPE_E:
                    109:                                reply(504, "Type E not implemented.");
                    110:                                break;
                    111: 
                    112:                        case TYPE_I:
                    113:                                reply(200, "Type set to I.");
                    114:                                type = cmd_type;
                    115:                                break;
                    116: 
                    117:                        case TYPE_L:
                    118:                                if (cmd_bytesz == 8) {
                    119:                                        reply(200,
                    120:                                            "Type set to L (byte size 8).");
                    121:                                        type = cmd_type;
                    122:                                } else
                    123:                                        reply(504, "Byte size must be 8.");
                    124:                        }
                    125:                }
                    126:        |       STRU SP struct_code CRLF
                    127:                = {
                    128:                        switch ($3) {
                    129: 
                    130:                        case STRU_F:
                    131:                                reply(200, "STRU F ok.");
                    132:                                break;
                    133: 
                    134:                        default:
                    135:                                reply(502, "Unimplemented STRU type.");
                    136:                        }
                    137:                }
                    138:        |       MODE SP mode_code CRLF
                    139:                = {
                    140:                        switch ($3) {
                    141: 
                    142:                        case MODE_S:
                    143:                                reply(200, "MODE S ok.");
                    144:                                break;
                    145: 
                    146:                        default:
                    147:                                reply(502, "Unimplemented MODE type.");
                    148:                        }
                    149:                }
                    150:        |       ALLO SP NUMBER CRLF
                    151:                = {
                    152:                        ack($1);
                    153:                }
                    154:        |       RETR check_login SP pathname CRLF
                    155:                = {
                    156:                        if ($2 && $4 != NULL)
                    157:                                retrieve(0, $4);
                    158:                        if ($4 != NULL)
                    159:                                free($4);
                    160:                }
                    161:        |       OPEN check_login SP pathname CRLF
                    162:                = {
                    163:                        if ($2 && $4 != NULL)
                    164:                                openfile($4);
                    165:                        if ($4 != NULL)
                    166:                                free($4);
                    167:                }
                    168:        |       STOR check_login SP pathname CRLF
                    169:                = {
                    170:                        if ($2 && $4 != NULL)
                    171:                                store($4, "w");
                    172:                        if ($4 != NULL)
                    173:                                free($4);
                    174:                }
                    175:        |       APPE check_login SP pathname CRLF
                    176:                = {
                    177:                        if ($2 && $4 != NULL)
                    178:                                store($4, "a");
                    179:                        if ($4 != NULL)
                    180:                                free($4);
                    181:                }
                    182:        |       NLST check_login CRLF
                    183:                = {
                    184:                        if ($2)
                    185:                                retrieve("/bin/ls", "");
                    186:                }
                    187:        |       NLST check_login SP pathname CRLF
                    188:                = {
                    189:                        if ($2 && $4 != NULL)
                    190:                                retrieve("/bin/ls %s", $4);
                    191:                        if ($4 != NULL)
                    192:                                free($4);
                    193:                }
                    194:        |       LIST check_login CRLF
                    195:                = {
                    196:                        if ($2)
                    197:                                retrieve("/bin/ls -lg", "");
                    198:                }
                    199:        |       LIST check_login SP pathname CRLF
                    200:                = {
                    201:                        if ($2 && $4 != NULL)
                    202:                                retrieve("/bin/ls -lg %s", $4);
                    203:                        if ($4 != NULL)
                    204:                                free($4);
                    205:                }
                    206:        |       DELE check_login SP pathname CRLF
                    207:                = {
                    208:                        if ($2 && $4 != NULL)
                    209:                                delete($4);
                    210:                        if ($4 != NULL)
                    211:                                free($4);
                    212:                }
                    213:        |       CWD check_login CRLF
                    214:                = {
                    215:                        if ($2)
                    216:                                cwd(pw->pw_dir);
                    217:                }
                    218:        |       CWD check_login SP pathname CRLF
                    219:                = {
                    220:                        if ($2 && $4 != NULL)
                    221:                                cwd($4);
                    222:                        if ($4 != NULL)
                    223:                                free($4);
                    224:                }
                    225:        |       rename_cmd
                    226:        |       HELP CRLF
                    227:                = {
                    228:                        help(0);
                    229:                }
                    230:        |       HELP SP STRING CRLF
                    231:                = {
                    232:                        help($3);
                    233:                }
                    234:        |       NOOP CRLF
                    235:                = {
                    236:                        ack($1);
                    237:                }
                    238:        |       PASV CRLF
                    239:                = {
                    240:                        pasv++;
                    241:                        ack($1);
                    242:                }
                    243:        |       XMKD check_login SP pathname CRLF
                    244:                = {
                    245:                        if ($2 && $4 != NULL)
                    246:                                makedir($4);
                    247:                        if ($4 != NULL)
                    248:                                free($4);
                    249:                }
                    250:        |       XRMD check_login SP pathname CRLF
                    251:                = {
                    252:                        if ($2 && $4 != NULL)
                    253:                                removedir($4);
                    254:                        if ($4 != NULL)
                    255:                                free($4);
                    256:                }
                    257:        |       XPWD check_login CRLF
                    258:                = {
                    259:                        if ($2)
                    260:                                pwd();
                    261:                }
                    262:        |       XCUP check_login CRLF
                    263:                = {
                    264:                        if ($2)
                    265:                                cwd("..");
                    266:                }
                    267:        |       QUIT CRLF
                    268:                = {
                    269:                        reply(221, "Goodbye.");
                    270:                        dologout(0);
                    271:                }
                    272:        |       error CRLF
                    273:                = {
                    274:                        yyerrok;
                    275:                }
                    276:        ;
                    277: 
                    278: username:      STRING
                    279:        ;
                    280: 
                    281: password:      STRING
                    282:        ;
                    283: 
                    284: byte_size:     NUMBER
                    285:        ;
                    286: 
                    287: host_port:     NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 
                    288:                NUMBER COMMA NUMBER
                    289:                = {
                    290:                        sprintf(dest, "tcp!%d.%d.%d.%d!%d",
                    291:                                $1, $3, $5, $7, $9 * 256 + $11);
                    292:                }
                    293:        ;
                    294: 
                    295: form_code:     N
                    296:        = {
                    297:                $$ = FORM_N;
                    298:        }
                    299:        |       T
                    300:        = {
                    301:                $$ = FORM_T;
                    302:        }
                    303:        |       C
                    304:        = {
                    305:                $$ = FORM_C;
                    306:        }
                    307:        ;
                    308: 
                    309: type_code:     A
                    310:        = {
                    311:                cmd_type = TYPE_A;
                    312:                cmd_form = FORM_N;
                    313:        }
                    314:        |       A SP form_code
                    315:        = {
                    316:                cmd_type = TYPE_A;
                    317:                cmd_form = $3;
                    318:        }
                    319:        |       E
                    320:        = {
                    321:                cmd_type = TYPE_E;
                    322:                cmd_form = FORM_N;
                    323:        }
                    324:        |       E SP form_code
                    325:        = {
                    326:                cmd_type = TYPE_E;
                    327:                cmd_form = $3;
                    328:        }
                    329:        |       I
                    330:        = {
                    331:                cmd_type = TYPE_I;
                    332:        }
                    333:        |       L
                    334:        = {
                    335:                cmd_type = TYPE_L;
                    336:                cmd_bytesz = 8;
                    337:        }
                    338:        |       L SP byte_size
                    339:        = {
                    340:                cmd_type = TYPE_L;
                    341:                cmd_bytesz = $3;
                    342:        }
                    343:        /* this is for a bug in the BBN ftp */
                    344:        |       L byte_size
                    345:        = {
                    346:                cmd_type = TYPE_L;
                    347:                cmd_bytesz = $2;
                    348:        }
                    349:        ;
                    350: 
                    351: struct_code:   F
                    352:        = {
                    353:                $$ = STRU_F;
                    354:        }
                    355:        |       R
                    356:        = {
                    357:                $$ = STRU_R;
                    358:        }
                    359:        |       P
                    360:        = {
                    361:                $$ = STRU_P;
                    362:        }
                    363:        ;
                    364: 
                    365: mode_code:     S
                    366:        = {
                    367:                $$ = MODE_S;
                    368:        }
                    369:        |       B
                    370:        = {
                    371:                $$ = MODE_B;
                    372:        }
                    373:        |       C
                    374:        = {
                    375:                $$ = MODE_C;
                    376:        }
                    377:        ;
                    378: 
                    379: pathname:      pathstring
                    380:        = {
                    381:                $$ = $1;
                    382:        }
                    383:        ;
                    384: 
                    385: pathstring:    STRING
                    386:        ;
                    387: 
                    388: rename_cmd:    rename_from rename_to
                    389:        = {
                    390:                if ($1 && $2)
                    391:                        renamecmd($1, $2);
                    392:                else
                    393:                        reply(503, "Bad sequence of commands.");
                    394:                if ($1)
                    395:                        free($1);
                    396:                if ($2)
                    397:                        free($2);
                    398:        }
                    399:        ;
                    400: 
                    401: rename_from:   RNFR check_login SP pathname CRLF
                    402:        = {
                    403:                char *from = 0, *renamefrom();
                    404: 
                    405:                if ($2 && $4)
                    406:                        from = renamefrom($4);
                    407:                if (from == 0 && $4)
                    408:                        free($4);
                    409:                $$ = (int)from;
                    410:        }
                    411:        ;
                    412: 
                    413: rename_to:     RNTO SP pathname CRLF
                    414:        = {
                    415:                $$ = $3;
                    416:        }
                    417:        ;
                    418: 
                    419: check_login:   /* empty */
                    420:        = {
                    421:                if (logged_in)
                    422:                        $$ = 1;
                    423:                else {
                    424:                        reply(530, "Please login with USER and PASS.");
                    425:                        $$ = 0;
                    426:                }
                    427:        }
                    428:        ;
                    429: 
                    430: %%
                    431: 
                    432: extern jmp_buf errcatch;
                    433: 
                    434: #define        CMD     0       /* beginniAg of command */
                    435: #define        ARGS    1       /* expect miscellaneous arguments */
                    436: #define        STR1    2       /* expect SP followed by STRING */
                    437: #define        STR2    3       /* expect STRING */
                    438: #define        OSTR    4       /* optional STRING */
                    439: 
                    440: struct tab {
                    441:        char    *name;
                    442:        short   token;
                    443:        short   state;
                    444:        short   implemented;    /* 1 if command is implemented */
                    445:        char    *help;
                    446: };
                    447: 
                    448: struct tab cmdtab[] = {                /* In order defined in RFC 765 */
                    449:        { "USER", USER, STR1, 1,        "<sp> username" },
                    450:        { "PASS", PASS, STR1, 1,        "<sp> password" },
                    451:        { "ACCT", ACCT, STR1, 0,        "(specify account)" },
                    452:        { "REIN", REIN, ARGS, 0,        "(reinitialize server state)" },
                    453:        { "QUIT", QUIT, ARGS, 1,        "(terminate service)", },
                    454:        { "PORT", PORT, ARGS, 1,        "<sp> b0, b1, b2, b3, b4" },
                    455:        { "PASV", PASV, ARGS, 1,        "(set server in passive mode)" },
                    456:        { "TYPE", TYPE, ARGS, 1,        "<sp> [ A | E | I | L ]" },
                    457:        { "STRU", STRU, ARGS, 1,        "(specify file structure)" },
                    458:        { "MODE", MODE, ARGS, 1,        "(specify transfer mode)" },
                    459:        { "RETR", RETR, STR1, 1,        "<sp> file-name" },
                    460:        { "STOR", STOR, STR1, 1,        "<sp> file-name" },
                    461:        { "APPE", APPE, STR1, 1,        "<sp> file-name" },
                    462:        { "MLFL", MLFL, OSTR, 0,        "(mail file)" },
                    463:        { "MAIL", MAIL, OSTR, 0,        "(mail to user)" },
                    464:        { "MSND", MSND, OSTR, 0,        "(mail send to terminal)" },
                    465:        { "MSOM", MSOM, OSTR, 0,        "(mail send to terminal or mailbox)" },
                    466:        { "MSAM", MSAM, OSTR, 0,        "(mail send to terminal and mailbox)" },
                    467:        { "MRSQ", MRSQ, OSTR, 0,        "(mail recipient scheme question)" },
                    468:        { "MRCP", MRCP, STR1, 0,        "(mail recipient)" },
                    469:        { "ALLO", ALLO, ARGS, 1,        "allocate storage (vacuously)" },
                    470:        { "REST", REST, STR1, 0,        "(restart command)" },
                    471:        { "RNFR", RNFR, STR1, 1,        "<sp> file-name" },
                    472:        { "RNTO", RNTO, STR1, 1,        "<sp> file-name" },
                    473:        { "ABOR", ABOR, ARGS, 0,        "(abort operation)" },
                    474:        { "DELE", DELE, STR1, 1,        "<sp> file-name" },
                    475:        { "CWD",  CWD,  OSTR, 1,        "[ <sp> directory-name]" },
                    476:        { "XCWD", CWD,  OSTR, 1,        "[ <sp> directory-name ]" },
                    477:        { "LIST", LIST, OSTR, 1,        "[ <sp> path-name ]" },
                    478:        { "NLST", NLST, OSTR, 1,        "[ <sp> path-name ]" },
                    479:        { "SITE", SITE, STR1, 0,        "(get site parameters)" },
                    480:        { "STAT", STAT, OSTR, 0,        "(get server status)" },
                    481:        { "HELP", HELP, OSTR, 1,        "[ <sp> <string> ]" },
                    482:        { "NOOP", NOOP, ARGS, 1,        "" },
                    483:        { "XMKD", XMKD, STR1, 1,        "<sp> path-name" },
                    484:        { "XRMD", XRMD, STR1, 1,        "<sp> path-name" },
                    485:        { "XPWD", XPWD, ARGS, 1,        "(return current directory)" },
                    486:        { "XCUP", XCUP, ARGS, 1,        "(change to parent directory)" },
                    487:        { "OPEN", OPEN, STR1, 1,        "[ <sp> path-name ]" },
                    488:        { "CLOS", CLOS, ARGS, 1,        "(close file)" },
                    489:        { "READ", READ, ARGS, 1,        "(read from file)" },
                    490:        { "WRIT", WRIT, ARGS, 1,        "(writ from file)" },
                    491:        { "SEEK", SEEK, ARGS, 1,        "(seek in file)" },
                    492:        { NULL,   0,    0,    0,        0 }
                    493: };
                    494: 
                    495: struct tab *
                    496: lookup(cmd)
                    497:        char *cmd;
                    498: {
                    499:        register struct tab *p;
                    500: 
                    501:        for (p = cmdtab; p->name != NULL; p++)
                    502:                if (strcmp(cmd, p->name) == 0)
                    503:                        return (p);
                    504:        return (0);
                    505: }
                    506: 
                    507: #include "telnet.h"
                    508: 
                    509: /*
                    510:  * getline - a hacked up version of fgets to ignore TELNET escape codes.
                    511:  */
                    512: char *
                    513: getline(s, n, iop)
                    514:        char *s;
                    515:        register FILE *iop;
                    516: {
                    517:        register c;
                    518:        register char *cs;
                    519: 
                    520:        cs = s;
                    521:        while (--n > 0 && (c = getc(iop)) >= 0) {
                    522:                while (c == IAC) {
                    523:                        c = getc(iop);  /* skip command */
                    524:                        c = getc(iop);  /* try next char */
                    525:                }
                    526:                *cs++ = c;
                    527:                if (c=='\n')
                    528:                        break;
                    529:        }
                    530:        if (c < 0 && cs == s)
                    531:                return (NULL);
                    532:        *cs++ = '\0';
                    533:        if (debug) {
                    534:                fprintf(stderr, "FTPD: command: %s", s);
                    535:                if (c != '\n')
                    536:                        putc('\n', stderr);
                    537:                fflush(stderr);
                    538:        }
                    539:        return (s);
                    540: }
                    541: 
                    542: static int
                    543: toolong()
                    544: {
                    545:        long now;
                    546:        extern char *ctime();
                    547: 
                    548:        reply(421,
                    549:          "Timeout (%d seconds): closing control connection.", timeout);
                    550:        time(&now);
                    551:        if (logging) {
                    552:                fprintf(stderr,
                    553:                        "FTPD: User %s timed out after %d seconds at %s",
                    554:                        (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
                    555:                fflush(stderr);
                    556:        }
                    557:        dologout(1);
                    558: }
                    559: 
                    560: yylex()
                    561: {
                    562:        static char cbuf[512];
                    563:        static int cpos, state;
                    564:        register char *cp;
                    565:        register struct tab *p;
                    566:        int n;
                    567:        char c;
                    568: 
                    569:        for (;;) {
                    570:                switch (state) {
                    571: 
                    572:                case CMD:
                    573:                        signal(SIGALRM, toolong);
                    574:                        alarm(timeout);
                    575:                        if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
                    576:                                reply(221, "You could at least say goodbye.");
                    577:                                dologout(0);
                    578:                        }
                    579:                        alarm(0);
                    580:                        if (strchr(cbuf, '\r')) {
                    581:                                cp = strchr(cbuf, '\r');
                    582:                                cp[0] = '\n'; cp[1] = 0;
                    583:                        }
                    584:                        if (strchr(cbuf, ' '))
                    585:                                cpos = strchr(cbuf, ' ') - cbuf;
                    586:                        else
                    587:                                cpos = 4;
                    588:                        c = cbuf[cpos];
                    589:                        cbuf[cpos] = '\0';
                    590:                        upper(cbuf);
                    591:                        p = lookup(cbuf);
                    592:                        cbuf[cpos] = c;
                    593:                        if (p != 0) {
                    594:                                if (p->implemented == 0) {
                    595:                                        nack(p->name);
                    596:                                        longjmp(errcatch);
                    597:                                        /* NOTREACHED */
                    598:                                }
                    599:                                state = p->state;
                    600:                                yylval = (int) p->name;
                    601:                                return (p->token);
                    602:                        }
                    603:                        break;
                    604: 
                    605:                case OSTR:
                    606:                        if (cbuf[cpos] == '\n') {
                    607:                                state = CMD;
                    608:                                return (CRLF);
                    609:                        }
                    610:                        /* FALL THRU */
                    611: 
                    612:                case STR1:
                    613:                        if (cbuf[cpos] == ' ') {
                    614:                                cpos++;
                    615:                                state = STR2;
                    616:                                return (SP);
                    617:                        }
                    618:                        break;
                    619: 
                    620:                case STR2:
                    621:                        cp = &cbuf[cpos];
                    622:                        n = strlen(cp);
                    623:                        cpos += n - 1;
                    624:                        /*
                    625:                         * Make sure the string is nonempty and \n terminated.
                    626:                         */
                    627:                        if (n > 1 && cbuf[cpos] == '\n') {
                    628:                                cbuf[cpos] = '\0';
                    629:                                yylval = copy(cp);
                    630:                                cbuf[cpos] = '\n';
                    631:                                state = ARGS;
                    632:                                return (STRING);
                    633:                        }
                    634:                        break;
                    635: 
                    636:                case ARGS:
                    637:                        if (isdigit(cbuf[cpos])) {
                    638:                                cp = &cbuf[cpos];
                    639:                                while (isdigit(cbuf[++cpos]))
                    640:                                        ;
                    641:                                c = cbuf[cpos];
                    642:                                cbuf[cpos] = '\0';
                    643:                                yylval = atoi(cp);
                    644:                                cbuf[cpos] = c;
                    645:                                return (NUMBER);
                    646:                        }
                    647:                        switch (cbuf[cpos++]) {
                    648: 
                    649:                        case '\n':
                    650:                                state = CMD;
                    651:                                return (CRLF);
                    652: 
                    653:                        case ' ':
                    654:                                return (SP);
                    655: 
                    656:                        case ',':
                    657:                                return (COMMA);
                    658: 
                    659:                        case 'A':
                    660:                        case 'a':
                    661:                                return (A);
                    662: 
                    663:                        case 'B':
                    664:                        case 'b':
                    665:                                return (B);
                    666: 
                    667:                        case 'C':
                    668:                        case 'c':
                    669:                                return (C);
                    670: 
                    671:                        case 'E':
                    672:                        case 'e':
                    673:                                return (E);
                    674: 
                    675:                        case 'F':
                    676:                        case 'f':
                    677:                                return (F);
                    678: 
                    679:                        case 'I':
                    680:                        case 'i':
                    681:                                return (I);
                    682: 
                    683:                        case 'L':
                    684:                        case 'l':
                    685:                                return (L);
                    686: 
                    687:                        case 'N':
                    688:                        case 'n':
                    689:                                return (N);
                    690: 
                    691:                        case 'P':
                    692:                        case 'p':
                    693:                                return (P);
                    694: 
                    695:                        case 'R':
                    696:                        case 'r':
                    697:                                return (R);
                    698: 
                    699:                        case 'S':
                    700:                        case 's':
                    701:                                return (S);
                    702: 
                    703:                        case 'T':
                    704:                        case 't':
                    705:                                return (T);
                    706: 
                    707:                        }
                    708:                        break;
                    709: 
                    710:                default:
                    711:                        fatal("Unknown state in scanner.");
                    712:                }
                    713:                yyerror();
                    714:                state = CMD;
                    715:                longjmp(errcatch);
                    716:        }
                    717: }
                    718: 
                    719: upper(s)
                    720:        char *s;
                    721: {
                    722:        while (*s != '\0') {
                    723:                if (islower(*s))
                    724:                        *s = toupper(*s);
                    725:                s++;
                    726:        }
                    727: }
                    728: 
                    729: copy(s)
                    730:        char *s;
                    731: {
                    732:        char *p;
                    733:        extern char *malloc();
                    734: 
                    735:        p = malloc(strlen(s) + 1);
                    736:        if (p == NULL)
                    737:                fatal("Ran out of memory.");
                    738:        strcpy(p, s);
                    739:        return ((int)p);
                    740: }
                    741: 
                    742: help(s)
                    743:        char *s;
                    744: {
                    745:        register struct tab *c;
                    746:        register int width, NCMDS;
                    747: 
                    748:        width = 0, NCMDS = 0;
                    749:        for (c = cmdtab; c->name != NULL; c++) {
                    750:                int len = strlen(c->name);
                    751: 
                    752:                if (c->implemented == 0)
                    753:                        len++;
                    754:                if (len > width)
                    755:                        width = len;
                    756:                NCMDS++;
                    757:        }
                    758:        width = (width + 8) &~ 7;
                    759:        if (s == 0) {
                    760:                register int i, j, w;
                    761:                int columns, lines;
                    762: 
                    763:                lreply(214,
                    764:          "The following commands are recognized (* =>'s unimplemented).");
                    765:                columns = 76 / width;
                    766:                if (columns == 0)
                    767:                        columns = 1;
                    768:                lines = (NCMDS + columns - 1) / columns;
                    769:                for (i = 0; i < lines; i++) {
                    770:                        printf("    ");
                    771:                        for (j = 0; j < columns; j++) {
                    772:                                c = cmdtab + j * lines + i;
                    773:                                printf("%s%c", c->name,
                    774:                                        c->implemented ? ' ' : '*');
                    775:                                if (c + lines >= &cmdtab[NCMDS])
                    776:                                        break;
                    777:                                w = strlen(c->name);
                    778:                                while (w < width) {
                    779:                                        putchar(' ');
                    780:                                        w++;
                    781:                                }
                    782:                        }
                    783:                        printf("\r\n");
                    784:                }
                    785:                fflush(stdout);
                    786:                reply(214, "Direct comments to ftp-bugs@%s.", hostname);
                    787:                return;
                    788:        }
                    789:        upper(s);
                    790:        c = lookup(s);
                    791:        if (c == (struct tab *)0) {
                    792:                reply(504, "Unknown command %s.", s);
                    793:                return;
                    794:        }
                    795:        if (c->implemented)
                    796:                reply(214, "Syntax: %s %s", c->name, c->help);
                    797:        else
                    798:                reply(214, "%-*s\t%s; unimplemented.", width, c->name, c->help);
                    799: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.