home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-02-02 | 37.2 KB | 1,625 lines |
- /* FTP client (interactive user) code */
- #define LINELEN 128 /* Length of command buffer */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include "alarm.h"
- #include "global.h"
- #include "mbuf.h"
- #include "domain.h"
- #include "netuser.h"
- #include "icmp.h"
- #include "timer.h"
- #include "tcp.h"
- #include "ftp.h"
- #include "session.h"
- #include "cmdparse.h"
- #include "misc.h"
- #include "Terminal.h"
- #include "vterm.h"
- #include "bbc.h"
- #include "files.h"
- #include "pathent.h"
- #include "var.h"
-
- extern varlist global_vars;
-
- extern os_error *create_path(char *path, int size, int type);
- extern char *fttoa(int t);
-
- extern struct session *current;
- struct session *current_ftp;
- extern char nospace[];
- extern char badhost[];
- static char notsess[] = "Not an FTP session!\r\n";
- static char cantwrite[] = "Can't write %s\r\n";
- static char cantread[] = "Can't read %s\r\n";
- static char nomemforop[] = "Insufficient memory for this operation\r\n";
-
- static int donothing(int, char **);
- static int doftpquit(int, char **);
- static int dowinclose(int, char **);
- static int dowinopen(int, char **);
- static int doftpcd(int, char **);
- static int domkdir(int, char **);
- static int dormdir(int, char **);
- static int doascii(int, char **);
- static int dobinary(int, char **);
- static int dotype(int, char **);
- static int doget(int, char **);
- static int doreget(int, char **);
- static int domget(int, char **);
- static int dobatch(int, char **);
- static int dopath(int, char **);
- static int doquote(int, char **);
- static int doview(int, char **);
- static int dohash(int, char **);
- static int dolist(int, char **);
- static int dols(int, char **);
- static int doput(int, char **);
- static void doreply(struct ftp *);
- static void ftpsetup(struct ftp *, void (*)(), void (*)(), void (*)());
- static void ftpccs(struct tcb *, char, char);
- static void ftpcds(struct tcb *, char, char);
- static int sndftpmsg(struct ftp *, char *, ...);
- static void prompt(struct ftp *ftp);
- static int batch_ftp(struct ftp *ftp);
- static int mprocess(struct ftp *ftp);
-
- void ftp_mpcleanup(struct ftp *ftp);
-
-
- struct cmds ftpabort[] = {
- "", donothing, 0, NULLCHAR, NULLCHAR,
- "abort", doabort, 0, NULLCHAR, NULLCHAR,
- "hash", dohash, 2, "hash lumpsize", NULLCHAR,
- NULLCHAR, NULLFP, 0, "Only valid command is \"abort\"", NULLCHAR,
- };
-
- struct cmds ftpcmds[] = {
- "", donothing, 0, NULLCHAR, NULLCHAR,
- "ascii", doascii, 0, NULLCHAR, NULLCHAR,
- "abort", doabort, 0, NULLCHAR, NULLCHAR,
- "binary", dobinary, 0, NULLCHAR, NULLCHAR,
- "cd", doftpcd, 2, "cd <directory>", NULLCHAR,
- "dir", dolist, 0, NULLCHAR, NULLCHAR,
- "list", dolist, 0, NULLCHAR, NULLCHAR,
- "get", doget, 2, "get remotefile <localfile>", NULLCHAR,
- "hash", dohash, 2, "hash lumpsize", NULLCHAR,
- "image", dobinary, 0, NULLCHAR, NULLCHAR,
- "ls", dols, 0, NULLCHAR, NULLCHAR,
- "mget", domget, 2, "mget <filelist>", NULLCHAR,
- "mkdir", domkdir, 2, "mkdir <directory>", NULLCHAR,
- "nlst", dols, 0, NULLCHAR, NULLCHAR,
- "path", dopath, 0, "path [<path process options>|off|default]", NULLCHAR,
- "put", doput, 2, "put localfile <remotefile>", NULLCHAR,
- "quote", doquote, 0, "quote <command>", NULLCHAR,
- "reget", doreget, 2, "reget remotefile <localfile>", NULLCHAR,
- "rmdir", dormdir, 2, "rmdir <directory>", NULLCHAR,
- "source", dobatch, 0, "source <ftp command file>", NULLCHAR,
- "type", dotype, 0, NULLCHAR, NULLCHAR,
- "view", doview, 1, "view remotefile", NULLCHAR,
- "winclose", dowinclose, 0, "winclose", NULLCHAR,
- "winopen", dowinopen, 0, "winopen", NULLCHAR,
- "quit", doftpquit, 0, "quit", NULLCHAR,
- "bye", doftpquit, 0, "bye", NULLCHAR,
- NULLCHAR, NULLFP, 0, NULLCHAR, NULLCHAR,
- };
-
- /* Handle top-level FTP command */
- int doftp(int argc, char **argv)
- {
- int used_args;
- struct session *s;
- struct ftp *ftp;
- struct tcb *tcb;
- struct socket lsocket,fsocket;
-
- lsocket.address = ip_addr;
- lsocket.port = lport++;
- if ((fsocket.address = resolve(argv[1])) == 0)
- {
- cwprintf(NULL, badhost,argv[1]);
- return 1;
- }
-
- if (argc<3)
- {
- fsocket.port = FTP_PORT;
- used_args = 2;
- }
- else
- {
- if (*argv[2]!='\\')
- {
- fsocket.port = atoi(argv[2]);
- used_args = 3;
- }
- else
- {
- fsocket.port = FTP_PORT;
- used_args = 2;
- }
- }
- /* Allocate a session control block */
- if ((s = newsession()) == NULLSESSION)
- {
- cwprintf(NULL, "Too many sessions\r\n");
- return 1;
- }
- if ((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
- strcpy(s->name,argv[1]);
- s->type = FTP;
- s->parse = (void(*)())ftpparse;
-
- /* Allocate an FTP control block */
- if ((ftp = ftp_create(LINELEN)) == NULLFTP)
- {
- s->type = FREE;
- cwprintf(NULL, nospace);
- return 1;
- }
- ftp->window = Window_Open(s, "FTP", term_SIXTEEN | term_CARET);
- vterm_parse(ftp->window->vt, argc-used_args, &argv[used_args]);
- current = s;
- ftp->state = STARTUP_STATE;
- s->cb.ftp = ftp; /* Downward link */
- ftp->session = s; /* Upward link */
- s->window = ftp->window;
- ftp->session->echo = TRUE;
-
- /* Now open the control connection */
- tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, 0, (void(*)())ftpccr, NULLVFP, (void(*)())ftpccs, 0,( char *)ftp);
- ftp->control = tcb;
- go(s);
- return 0;
- }
-
- /* Parse user FTP commands */
- void ftpparse(struct session *active, char *line, int16 len)
- {
- struct mbuf *bp;
- extern struct cmds cmds[];
- if (active == NULL)
- active = current;
- current_ftp = active;
-
- /* direct '*' prefixed commands to main command window */
- if (*line=='*')
- {
- cmdparse(cmds, line+1, NULL);
- prompt(active->cb.ftp);
- return;
- }
-
- switch(active->cb.ftp->state)
- {
- case RECEIVING_STATE:
- case SENDING_FILE_STATE:
- /* The only command allowed in data transfer state is ABORT */
- if (cmdparse(ftpabort, line, active->window) == -1)
- {
- cwprintf(active->window, "Transfer in progress; only ABORT is acceptable\r\n");
- }
- break;
- case COMMAND_STATE:
- /* Save it now because cmdparse modifies the original */
- bp = qdata(line,len);
- if (cmdparse(ftpcmds, line, active->window) == -1)
- {
- /* Send it direct */
- if (bp != NULLBUF)
- send_tcp(active->cb.ftp->control,bp);
- else
- cwprintf(active->window, nospace);
- }
- else
- {
- free_p(bp);
- }
- break;
- case STARTUP_STATE: /* Startup up autologin */
- cwprintf(active->window, "Not connected yet, ignoring %s\r\n",line);
- break;
- case USER_STATE: /* Got the user name */
- line[len] = '\0';
- sndftpmsg(active->cb.ftp,"USER %s",line);
- break;
- case PASS_STATE: /* Got the password */
- cooked();
- active->raw = FALSE;
- vterm_setflags(active->window->vt,
- /* Clear */ VTSW_CHAT|VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO,
- /* Set */ VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO );
- line[len] = '\0';
- sndftpmsg(active->cb.ftp,"PASS %s",line);
- break;
- }
- }
-
- /* Handle null line to avoid trapping on first command in table */
- static int donothing(int argc, char **argv)
- {
- argc = argc;
- argv = argv;
- return 0;
- }
-
- static int dowinclose(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
- argv = argv;
-
- ftp = current_ftp->cb.ftp;
- vterm_close(current_ftp->window->vt);
- current_ftp->window->Flags.flags.closing = 1;
- prompt(ftp);
-
- return 0;
- }
-
- static int dowinopen(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
- argv = argv;
-
- ftp = current_ftp->cb.ftp;
- vterm_open(current_ftp->window->vt);
- current_ftp->window->Flags.flags.closing = 0;
- prompt(ftp);
-
- return 0;
- }
-
- static int doftpquit(int argc, char **argv)
- {
- int a;
- register struct ftp *ftp;
-
- argc = argc;
-
- ftp = current_ftp->cb.ftp;
- a = sndftpmsg(ftp,"QUIT\r\n");
- prompt(ftp);
-
- return a;
- }
-
-
- /* Translate 'cd' to 'cwd' for convenience */
- static int doftpcd(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
-
- ftp = current_ftp->cb.ftp;
- return sndftpmsg(ftp,"CWD %s\r\n",argv[1]);
- }
-
- /* Translate 'mkdir' to 'xmkd' for convenience */
- static int domkdir(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
-
- ftp = current_ftp->cb.ftp;
- return sndftpmsg(ftp,"XMKD %s\r\n",argv[1]);
- }
-
- static int dohash(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
-
- ftp = current_ftp->cb.ftp;
- ftp->hash = atoi(argv[1]);
- ftp->last = 0;
-
- prompt(ftp);
- return(0);
- }
-
- /* Translate 'rmdir' to 'xrmd' for convenience */
- static int dormdir(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
-
- ftp = current_ftp->cb.ftp;
- return sndftpmsg(ftp,"XRMD %s\r\n",argv[1]);
- }
-
- static int dobinary(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
- argv = argv;
-
- ftp = current_ftp->cb.ftp;
- ftp->type = IMAGE_TYPE;
- sndftpmsg(ftp,"TYPE I\r\n");
-
- return(0);
- }
-
- static int doascii(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
- argv = argv;
-
- ftp = current_ftp->cb.ftp;
- ftp->type = ASCII_TYPE;
- sndftpmsg(ftp,"TYPE A\r\n");
-
- return(0);
- }
-
- /* Handle "type" command from user */
- static int dotype(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- ftp = current_ftp->cb.ftp;
- if (argc < 2)
- {
- switch(ftp->type)
- {
- case IMAGE_TYPE:
- cwprintf(ftp->window, "Image\r\n");
- break;
- case ASCII_TYPE:
- cwprintf(ftp->window, "Ascii\r\n");
- break;
- }
- return 0;
- }
- switch(*argv[1])
- {
- case 'i':
- case 'b':
- ftp->type = IMAGE_TYPE;
- sndftpmsg(ftp,"TYPE I\r\n");
- break;
- case 'a':
- ftp->type = ASCII_TYPE;
- sndftpmsg(ftp,"TYPE A\r\n");
- break;
- case 'l':
- ftp->type = IMAGE_TYPE;
- sndftpmsg(ftp,"TYPE L %s\r\n",argv[2]);
- break;
- default:
- cwprintf(ftp->window, "Invalid type %s\r\n",argv[1]);
- return 1;
- }
- return 0;
- }
-
- /* Verbatim command to server */
- static int doquote(int argc, char **argv)
- {
- char localname[256];
- register struct ftp *ftp;
-
- ftp = current_ftp->cb.ftp;
- if (ftp == NULLFTP)
- {
- cwprintf(ftp->window, notsess);
- return 1;
- }
-
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->restart = 0;
-
- ftp->fp = NULLFILE;
-
- if (argc < 3)
- {
- ftp->fp = stdout;
- }
- else
- {
- if (strchr(argv[2], '.'))
- strcpy(localname, argv[2]);
- else
- sprintf(localname, "<ftp$dir>.%s", argv[2]);
-
- /* Set variable to name of most recent file */
- var_create_string(global_vars, "ftp_list", 0, localname);
-
- if ((ftp->fp = fopen(localname, "w")), ftp->fp == NULLFILE)
- {
- cwprintf(ftp->window, cantwrite,argv[2]);
- return 1;
- }
- }
-
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- if ( ftp->type == IMAGE_TYPE )
- {
- ftp->type = IMAGE_PENDING ;
- sndftpmsg(ftp,"TYPE A\r\n");
- }
- ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
- /* Generate the command to start the transfer */
- return sndftpmsg(ftp,"%s\r\n",argv[1]);
- }
-
-
- /* Set current path processing options */
- static int dopath(int argc, char **argv)
- {
- int i, n;
- struct ftp *ftp;
- char opts[256];
- char *p;
- pathent_str *pe;
-
- ftp = current_ftp->cb.ftp;
-
- if (ftp == NULLFTP)
- {
- cwprintf(NULL, notsess);
- return 1;
- }
-
- if (argc>1)
- {
- if ((argc==2) && !strncmp(argv[1], "off", strlen(argv[1])))
- {
- delpathent(ftp->pathopts);
- ftp->pathopts = PATH_OFF;
- }
- else if ((argc==2) && !strncmp(argv[1], "auto", strlen(argv[1])))
- {
- delpathent(ftp->pathopts);
- ftp->pathopts = PATH_DEF;
- }
- else if ((argc==2) && !strncmp(argv[1], "type", strlen(argv[1])))
- {
- delpathent(ftp->pathopts);
- ftp->pathopts = PATH_TYPE;
- }
- else
- {
- /* Reconstrunct original path command */
- *opts = '$';
- p = opts+1;
- for (i=1; i<argc; i++)
- {
- n = sprintf(p, " %s", argv[i]);
- p += n;
- }
- if (pe = getpathent(opts), pe!=NULL)
- {
- delpathent(ftp->pathopts);
- ftp->pathopts = pe;
- }
- else
- {
- cwprintf(ftp->window, "Parse error in path options.\r\n");
- prompt(ftp);
- return 1;
- }
- }
- }
- else
- {
- if (ftp->pathopts == PATH_OFF)
- cwprintf(ftp->window, "Path processing off\r\n");
- else if (ftp->pathopts == PATH_DEF)
- cwprintf(ftp->window, "Auto path processing by extension\r\n");
- else
- cwprintf(ftp->window, "Preset path processing\r\n");
- /* show_pathent(ftp->pathopts); */
- }
-
- prompt(ftp);
- return 0;
- }
-
- /* Start processing a batch file. */
- static int dobatch(int argc, char **argv)
- {
- extern char scripts[];
-
- struct ftp *ftp;
- char file[256];
-
- ftp = current_ftp->cb.ftp;
-
- if (ftp == NULLFTP)
- {
- cwprintf(NULL, notsess);
- return 1;
- }
-
- if (ftp->batch!=NULL)
- {
- cwprintf(ftp->window, "Batch allready in progress.\r\n");
- return 1;
- }
-
- if (argc<2)
- {
- cwprintf(ftp->window, "No batch in progress.\r\n");
- return 0;
- }
-
- if (strpbrk(argv[1], "@&%$:<>"))
- sprintf(file, "%s", argv[1]);
- else
- sprintf(file, "%s.%s", scripts, argv[1]);
-
- if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
- goto opened;
-
- sprintf(file, "%s%s", RESROOT, argv[1]);
-
- if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
- goto opened;
-
- sprintf(file, "%s^.%s", RESROOT, argv[1]);
-
- if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
- goto opened;
-
- sprintf(file, "@.%s", argv[1]);
-
- if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
- goto opened;
-
- sprintf(file, "$.%s", argv[1]);
-
- if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
- goto opened;
-
- cwprintf(ftp->window, "Cant find batch file \"%s\".\r\n", argv[1]);
- return 1;
-
- opened:
- prompt(ftp);
- return 0;
- }
-
- /* Start receive transfer. Syntax: get <remote name> [<local name>] */
- static int doget(int argc, char **argv)
- {
- os_error *e;
- char *remotename, *temp, *cp, localname[256];
- register struct ftp *ftp;
- char *mode;
- int filetype = -1;
-
- ftp = current_ftp->cb.ftp;
- if (ftp == NULLFTP)
- {
- cwprintf(NULL, notsess);
- return 1;
- }
- remotename = argv[1];
-
- /*
- bbc_vdu(4);
- bbc_vdu(26);
- bbc_vdu(30);
- */
- if (argc < 3)
- {
- if (ftp->pathopts==PATH_OFF ||
- !pathmap(remotename, localname, &filetype, ftp->pathopts) ||
- ftp->pathopts==PATH_TYPE)
- {
- temp = strdup(remotename);
- cp = temp;
- while (cp = strpbrk(cp, "\"[]|<>+=;,./\\"), cp != NULL)
- {
- if (*cp=='/' || *cp=='\\')
- *cp++ = '.';
- else if (*cp=='.')
- *cp++ = '/';
- else
- *cp++ = '_';
- }
- /*
- if (strlen(temp) > 10)
- temp[10] = '\0';
- */
- sprintf(localname, "<FTP$dir>.%s", (*temp=='.')?temp+1:temp);
- free(temp);
- }
- if (filetype<0)
- filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
- }
- else
- {
- if (ftp->pathopts!=PATH_OFF)
- pathmap(remotename, localname, &filetype, PATH_TYPE);
-
- if (strpbrk(argv[2], "$&%<>:"))
- strcpy(localname, argv[2]);
- else
- sprintf(localname, "<FTP$Dir>.%s", argv[2]);
- if (filetype<0)
- filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
- }
- /*
- printf("file: %s, type: %.3x\n", localname, filetype);
- */
- cwprintf(ftp->window,"Opening %s (%s)\r\n", localname, fttoa(filetype));
-
- /* Set variable to name of most recent file */
- var_create_string(global_vars, "ftp_data", 0, localname);
-
- /* creates the file, ensuring a path is present */
- if (e = create_path(localname, 0, filetype), e!=NULL)
- {
- cwprintf(ftp->window,"Cant create local file - %s\n", e->errmess);
- return 1;
- }
-
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->restart = 0;
-
- ftp->fp = NULLFILE;
-
- if (ftp->type == IMAGE_PENDING)
- {
- ftp->type = IMAGE_TYPE ;
- sndftpmsg(ftp,"TYPE I\r\n");
- }
-
- if (ftp->type == IMAGE_TYPE)
- mode = binmode[WRITE_BINARY];
- else
- mode = "w";
-
- if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
- {
- cwprintf(ftp->window, cantwrite, localname);
- return 1;
- }
- if (ftp->type == IMAGE_TYPE)
- setvbuf(ftp->fp, NULL, _IOFBF, 16384);
-
- ftp->filetype = filetype;
- ftp->last = 0;
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
-
- /* Generate the command to start the transfer */
- return sndftpmsg(ftp,"RETR %s\r\n",remotename);
- }
-
- static int doreget(int argc, char **argv)
- {
- os_error *e;
- char *remotename, *temp, *cp, localname[256];
- register struct ftp *ftp;
- char *mode;
- int filetype = -1;
-
- ftp = current_ftp->cb.ftp;
- if (ftp == NULLFTP)
- {
- cwprintf(NULL, notsess);
- return 1;
- }
- remotename = argv[1];
-
- /*
- bbc_vdu(4);
- bbc_vdu(26);
- bbc_vdu(30);
- */
- if (argc < 3)
- {
- if (ftp->pathopts==PATH_OFF ||
- !pathmap(remotename, localname, &filetype, ftp->pathopts) ||
- ftp->pathopts==PATH_TYPE)
- {
- temp = strdup(remotename);
- cp = temp;
- while (cp = strpbrk(cp, "\"[]|<>+=;,./\\"), cp != NULL)
- {
- if (*cp=='/' || *cp=='\\')
- *cp++ = '.';
- else if (*cp=='.')
- *cp++ = '/';
- else
- *cp++ = '_';
- }
- /*
- if (strlen(temp) > 10)
- temp[10] = '\0';
- */
- sprintf(localname, "<FTP$dir>.%s", (*temp=='.')?temp+1:temp);
- free(temp);
- }
- if (filetype<0)
- filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
- }
- else
- {
- if (ftp->pathopts!=PATH_OFF)
- pathmap(remotename, localname, &filetype, PATH_TYPE);
-
- if (strpbrk(argv[2], "$&%<>:"))
- strcpy(localname, argv[2]);
- else
- sprintf(localname, "<FTP$Dir>.%s", argv[2]);
- if (filetype<0)
- filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
- }
- /*
- printf("file: %s, type: %.3x\n", localname, filetype);
- */
- cwprintf(ftp->window,"Opening %s (%s)\r\n", localname, fttoa(filetype));
-
- /* Set variable to name of most recent file */
- var_create_string(global_vars, "ftp_data", 0, localname);
-
- /* creates the file, ensuring a path is present */
- if (e = create_path(localname, 0, filetype), e!=NULL)
- {
- cwprintf(ftp->window,"Cant create local file - %s\n", e->errmess);
- return 1;
- }
-
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
-
- ftp->fp = NULLFILE;
-
- if (ftp->type == IMAGE_PENDING)
- {
- ftp->type = IMAGE_TYPE ;
- sndftpmsg(ftp,"TYPE I\r\n");
- }
-
- if (ftp->type == IMAGE_TYPE)
- mode = "ab";
- else
- mode = "a";
-
- if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
- {
- cwprintf(ftp->window, cantwrite, localname);
- return 1;
- }
- if (ftp->type == IMAGE_TYPE)
- setvbuf(ftp->fp, NULL, _IOFBF, 16384);
-
- ftp->restart = ftell(ftp->fp);
-
- ftp->filetype = filetype;
- ftp->last = 0;
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
-
- /* Generate the commands to start the transfer */
- sndftpmsg(ftp,"REST %ld\r\n",ftp->restart);
- return sndftpmsg(ftp,"RETR %s\r\n",remotename);
- }
-
- /* Start receive transfer. Syntax: view <remote name> */
- static int doview(int argc, char **argv)
- {
- char *remotename;
- register struct ftp *ftp;
-
- ftp = current_ftp->cb.ftp;
- if (ftp == NULLFTP)
- {
- cwprintf(ftp->window, notsess);
- return 1;
- }
- remotename = argv[1];
-
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- ftp->restart = 0;
-
- if (ftp->type == IMAGE_PENDING)
- {
- ftp->type = IMAGE_TYPE ;
- sndftpmsg(ftp,"TYPE I\r\n");
- }
-
- ftp->fp = stdout ;
- ftp->last = 0;
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
-
- /* Generate the command to start the transfer */
- return sndftpmsg(ftp,"RETR %s\r\n",remotename);
- }
-
- /* List remote directory. Syntax: dir <remote directory/file> [<local name>] */
- static int dolist(int argc, char **argv)
- {
- char localname[256];
- register struct ftp *ftp;
-
- ftp = current_ftp->cb.ftp;
- if (ftp == NULLFTP)
- {
- cwprintf(ftp->window, notsess);
- return 1;
- }
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- ftp->restart = 0;
-
- if (argc < 3)
- {
- ftp->fp = stdout;
- }
- else
- {
- if (strchr(argv[2], '.'))
- strcpy(localname, argv[2]);
- else
- sprintf(localname, "<ftp$dir>.%s", argv[2]);
-
- /* Set variable to name of most recent file */
- var_create_string(global_vars, "ftp_list", 0, localname);
-
- if ((ftp->fp = fopen(localname, "w")), ftp->fp == NULLFILE)
- {
- cwprintf(ftp->window, cantwrite,argv[2]);
- return 1;
- }
- }
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
- /* Generate the command to start the transfer
- It's done this way to avoid confusing the 4.2 FTP server
- if there's no argument */
- if (argc > 1)
- {
- if ( ftp->type == IMAGE_TYPE )
- {
- ftp->type = IMAGE_PENDING ;
- sndftpmsg(ftp,"TYPE A\r\n");
- }
- return sndftpmsg(ftp,"LIST %s\r\n",argv[1]);
- }
- else
- {
- if ( ftp->type == IMAGE_TYPE )
- {
- ftp->type = IMAGE_PENDING ;
- sndftpmsg(ftp,"TYPE A\r\n");
- }
- return sndftpmsg(ftp,"LIST\r\n","");
- }
- }
- /* Abbreviated (name only) list of remote directory.
- * Syntax: ls <remote directory/file> [<local name>]
- */
- static int dols(int argc, char **argv)
- {
- char localname[256];
- register struct ftp *ftp;
-
- ftp = current_ftp->cb.ftp;
- if (ftp == NULLFTP)
- {
- cwprintf(ftp->window, notsess);
- return 1;
- }
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- ftp->restart = 0;
-
- if (argc < 3)
- {
- ftp->fp = stdout;
- }
- else
- {
- if (strchr(argv[2], '.'))
- strcpy(localname, argv[2]);
- else
- sprintf(localname, "<ftp$dir>.%s", argv[2]);
-
- /* Set variable to name of most recent file */
- var_create_string(global_vars, "ftp_list", 0, localname);
-
- if ((ftp->fp = fopen(localname, "w")), ftp->fp == NULLFILE)
- {
- cwprintf(ftp->window, cantwrite,argv[2]);
- return 1;
- }
- }
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- if ( ftp->type == IMAGE_TYPE )
- {
- ftp->type = IMAGE_PENDING ;
- sndftpmsg(ftp,"TYPE A\r\n");
- }
- ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
- /* Generate the command to start the transfer */
- if (argc > 1)
- {
- return sndftpmsg(ftp,"NLST %s\r\n",argv[1]);
- }
- else
- {
- return sndftpmsg(ftp,"NLST\r\n","");
- }
- }
- /* Start transmit. Syntax: put <local name> [<remote name>] */
- static int doput(int argc, char **argv)
- {
- char *remotename,*localname;
- char *mode;
- struct ftp *ftp;
-
- if ((ftp = current_ftp->cb.ftp) == NULLFTP)
- {
- cwprintf(ftp->window, notsess);
- return 1;
- }
- localname = argv[1];
- if (argc < 3)
- remotename = localname;
- else
- remotename = argv[2];
-
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->restart = 0;
-
- if (ftp->type == IMAGE_PENDING)
- {
- ftp->type = IMAGE_TYPE ;
- sndftpmsg(ftp,"TYPE I\r\n");
- }
-
- if (ftp->type == IMAGE_TYPE)
- mode = binmode[READ_BINARY];
- else
- mode = "r";
-
- if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
- {
- cwprintf(ftp->window, cantread,localname);
- return 1;
- }
- fseek(ftp->fp,0,SEEK_END);
- ftp->expected_size = ftell(ftp->fp);
- fseek(ftp->fp,0,SEEK_SET);
- ftp->last = 0;
- ftp->state = SENDING_FILE_STATE;
- ftp->start_time = alarm_timenow () ;
- ftpsetup(ftp, NULLVFP, (void(*)())ftpdt, (void(*)())ftpcds);
-
- /* Generate the command to start the transfer */
- return sndftpmsg(ftp,"STOR %s\r\n",remotename);
- }
- /* Abort a GET or PUT operation in progress. Note: this will leave
- * the partial file on the local or remote system
- */
- int doabort(int argc, char **argv)
- {
- register struct ftp *ftp;
-
- argc = argc;
- argv = argv;
-
- ftp = current_ftp->cb.ftp;
-
- /* Close the local file */
- if (ftp->fp != NULLFILE && ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
-
- ftp->restart = 0;
-
- ftp_mpcleanup(ftp);
-
- if (ftp->batch)
- {
- cwprintf(ftp->window, "Batch file closed\r\n");
- fclose(ftp->batch);
- ftp->batch = NULL;
- }
-
- switch(ftp->state)
- {
- case SENDING_FILE_STATE:
- /* Send a premature EOF.
- Unfortunately we can't just reset the connection
- since the remote side might end up waiting forever
- for us to send something. */
- close_tcp(ftp->data);
- cwprintf(ftp->window, "Put aborted\r\n");
- break;
- case RECEIVING_STATE:
- /* Just exterminate the data channel TCB; this will
- * generate a RST on the next data packet which will
- * abort the sender
- */
- del_tcp(ftp->data);
- ftp->data = NULLTCB;
- cwprintf(ftp->window, "Get aborted\r\n");
- break;
- }
-
- ftp->state = COMMAND_STATE;
- prompt(ftp);
- return 0;
- }
- /* create data port, and send PORT message */
- static void ftpsetup(struct ftp *ftp, void (*recv)(),
- void (*send)(), void (*state)())
- {
- struct socket lsocket;
- struct mbuf *bp;
-
- lsocket.address = ip_addr;
- lsocket.port = lport++;
-
- /* Compose and send PORT a,a,a,a,p,p message */
-
- if ((bp = alloc_mbuf(35)) == NULLBUF)
- { /* 5 more than worst case */
- cwprintf(ftp->window, nospace);
- return;
- }
- /* I know, this looks gross, but it works! */
- sprintf(bp->data,"PORT %u,%u,%u,%u,%u,%u\r\n",
- hibyte(hiword(lsocket.address)),
- lobyte(hiword(lsocket.address)),
- hibyte(loword(lsocket.address)),
- lobyte(loword(lsocket.address)),
- hibyte(lsocket.port),
- lobyte(lsocket.port) );
- bp->cnt = strlen(bp->data);
- send_tcp(ftp->control,bp);
-
- /* Post a listen on the data connection */
- ftp->data = open_tcp(&lsocket,NULLSOCK,TCP_PASSIVE,0,
- recv,send,state,0,(char *)ftp);
- }
-
- /* FTP Client Control channel Receiver upcall routine */
- void ftpccr(register struct tcb *tcb, int16 cnt)
- {
- extern int ttyflow;
- struct mbuf *bp;
- struct ftp *ftp;
- char c;
-
- if ((ftp = (struct ftp *)tcb->user) == NULLFTP)
- {
- /* Unknown connection; kill it */
- close_tcp(tcb);
- return;
- }
- /* Hold output if we're not the current session */
- if (ftp->window == NULL && (mode != CONV_MODE || current == NULLSESSION
- || ttyflow == 0 || current->cb.ftp != ftp))
- return;
-
- if (recv_tcp(tcb,&bp,cnt) > 0)
- {
- while(pullone(&bp,&c) == 1)
- {
- switch(c)
- {
- case '\n': /* Complete line; process it */
-
- ftp->buf[ftp->cnt] = '\0';
- doreply(ftp);
- ftp->cnt = 0;
- break;
- default:
- if (ftp->cnt != LINELEN-1)
- ftp->buf[ftp->cnt++] = c;
- break;
- }
- }
- }
- }
-
- int extract_line_number ( char * l )
- {
- int i = 0 , c ;
-
- for ( c = 0 ; c < 3 ; c ++ )
- {
- if ( isdigit ( l [c] ) )
- {
- i = i * 10 + ( l [c] - '0' ) ;
- }
- else
- {
- c = 3 ;
- }
- }
- return ( i ) ;
- }
-
- /* Process replies from the server */
- static void doreply(register struct ftp *ftp)
- {
- char **s;
-
- cwprintf(ftp->window, "%s\r\n",ftp->buf);
-
- if (ftp->cnt < 3)
- return;
-
- if ( ftp->state == CONTINUATION_STATE )
- {
- if ( ftp->continue_val == extract_line_number ( ftp->buf ) )
- {
- ftp->state = ftp->last_state ;
- }
- else
- {
- return;
- }
- }
-
- if (ftp->buf[3] == '-')
- {
- ftp->last_state = ftp->state ;
- ftp->state = CONTINUATION_STATE ;
- ftp->continue_val = extract_line_number ( ftp->buf ) ;
- return;
- }
-
- switch(ftp->state)
- {
- case SENDING_FILE_STATE:
- case RECEIVING_STATE:
- if (ftp->buf[0] == '5')
- doabort(0, s);
- else if ( extract_line_number ( ftp->buf ) == 150 )
- {
- /* Opening message - see if we can find a file size... */
- char *s = strchr(ftp->buf , '(');
-
- if (sscanf(s, "(%lu bytes)", &ftp->expected_size) < 1)
- {
- ftp->expected_size = 0;
- }
- }
- break;
- case STARTUP_STATE:
- if (strncmp(ftp->buf, "220", 3) == 0)
- {
- ftp->state = USER_STATE;
- cwprintf(ftp->window, "Enter user name: ");
- }
- else ftp->state = COMMAND_STATE;
- break;
- case USER_STATE:
- if (strncmp(ftp->buf, "331", 3) == 0)
- {
- ftp->state = PASS_STATE;
- noecho();
- ftp->session->echo = FALSE;
- cwprintf(ftp->window, "Password: ");
- vterm_setflags(ftp->window->vt,VTSW_ECHO,0);
- }
- else ftp->state = COMMAND_STATE;
- break;
- case PASS_STATE:
- echo();
- ftp->session->echo = TRUE;
- ftp->state = COMMAND_STATE;
- vterm_setflags(ftp->window->vt,VTSW_ECHO,VTSW_ECHO);
- case COMMAND_STATE:
- prompt(ftp);
- break;
- }
- }
-
- /* FTP Client Control channel State change upcall routine */
- static void ftpccs(register struct tcb *tcb, char old, char new)
- {
- extern int ttyflow;
- struct ftp *ftp;
- char notify = 0;
- extern char *tcpstates[];
- extern char *reasons[];
- extern char *unreach[];
- extern char *exceed[];
-
- old = old;
-
- /* Can't add a check for unknown connection here, it would loop
- * on a close upcall! We're just careful later on.
- */
- ftp = (struct ftp *)tcb->user;
-
- if (ftp->window || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
- notify = 1;
-
- switch(new)
- {
- case CLOSE_WAIT:
- if (notify)
- cwprintf(ftp->window, "%s\r\n",tcpstates[new]);
- close_tcp(tcb);
- break;
- case CLOSED: /* heh heh */
- if (notify)
- {
- cwprintf(ftp->window, "%s (%s",tcpstates[new],reasons[tcb->reason]);
- if (tcb->reason == NETWORK)
- {
- switch(tcb->type)
- {
- case DEST_UNREACH:
- cwprintf(ftp->window, ": %s unreachable",unreach[tcb->code]);
- break;
- case TIME_EXCEED:
- cwprintf(ftp->window, ": %s time exceeded",exceed[tcb->code]);
- break;
- }
- }
- cwprintf(ftp->window, ")\r\n");
- cmdmode();
- }
- del_tcp(tcb);
- if (ftp != NULLFTP)
- {
- if (ftp->window)
- {
- ftp->window->Attr = ATTR_REVERSE;
- ftp->window->Flags.flags.dont_destroy = FALSE;
- ftp->window->Session = NULL;
- Window_CloseDown(ftp->window);
- }
- ftp_delete(ftp);
- }
- break;
- default:
- if (notify)
- cwprintf(ftp->window, "%s\r\n",tcpstates[new]);
- break;
- }
- }
- /* FTP Client Data channel State change upcall handler */
- static void ftpcds(struct tcb *tcb, char old, char new)
- {
- extern int ttyflow;
- struct ftp *ftp;
-
- old = old;
-
- if ((ftp = (struct ftp *)tcb->user) == NULLFTP)
- {
- /* Unknown connection, kill it */
- close_tcp(tcb);
- return;
- }
- switch(new)
- {
- case FINWAIT2:
- case TIME_WAIT:
- if (ftp->state == SENDING_FILE_STATE)
- {
- /* We've received an ack of our FIN, so
- * return to command mode
- */
- ftp->state = COMMAND_STATE;
- if (ftp->window != NULL || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
- {
- int a = alarm_timedifference(ftp->start_time, alarm_timenow()) / 100;
- long b = tcb->snd.una - tcb->iss - 2;
-
- if (ftp->hash > 0)
- cwputchar(ftp->window, '\n');
- if (a == 0)
- a++;
- cwprintf(ftp->window, "Put complete, %lu bytes sent (%lu cps)\r\n", b, b/a);
- prompt(ftp);
- }
- }
- break;
- case CLOSE_WAIT:
- close_tcp(tcb);
- if (ftp->state == RECEIVING_STATE)
- {
- /* End of file received on incoming file */
- if (ftp->fp != stdout)
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- ftp->state = COMMAND_STATE;
- if (ftp->window != NULL || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
- {
- int a = alarm_timedifference(ftp->start_time, alarm_timenow()) / 100;
- long b = tcb->rcv.nxt - tcb->irs - 2;
-
- if ( ftp->hash > 0 )
- cwputchar(ftp->window, '\n');
- if (a == 0)
- a++;
- if (ftp->restart)
- cwprintf(ftp->window, "Get complete, remaining %lu of %lu bytes received (%lu cps)\r\n",
- b, b+ftp->restart, b/a);
- else
- cwprintf(ftp->window, "Get complete, %lu bytes received (%lu cps)\r\n", b, b/a);
- prompt(ftp);
- }
- ftp->restart = 0;
- }
- break;
- case CLOSED:
- ftp->data = NULLTCB;
- del_tcp(tcb);
- break;
- }
- }
-
- /* Send a message on the control channel */
- static int sndftpmsg(struct ftp *ftp, char *fmt, ...)
- {
- va_list argptr;
- struct mbuf *bp;
- int16 len;
-
- va_start(argptr,fmt);
- len = strlen(fmt) + strlen(va_arg(argptr,char *)) + 10; /* fudge factor */
- va_end(argptr);
- if ((bp = alloc_mbuf(len)) == NULLBUF)
- {
- cwprintf(ftp->window, nospace);
- return 1;
- }
- va_start(argptr,fmt);
- vsprintf(bp->data,fmt,argptr);
- va_end(argptr);
- bp->cnt = strlen(bp->data);
- send_tcp(ftp->control,bp);
- return 0;
- }
-
- static void prompt(struct ftp *ftp)
- {
- if (ftp->state==RECEIVING_STATE || ftp->state==SENDING_FILE_STATE)
- cwprintf(ftp->window, "%s- ",(ftp->batch)?"batch":(ftp->mpstate==FTPM_IDLE)?"ftp":"mget");
- else if (!mprocess(ftp) && !batch_ftp(ftp))
- cwprintf(ftp->window, "ftp> ");
- }
-
- static int batch_ftp(struct ftp *ftp)
- {
- char *p;
- char buf[256];
-
- if (!ftp->batch)
- return 0;
-
- cwprintf(ftp->window, "batch> ");
-
- do
- {
- p = fgets(buf, 256, ftp->batch);
- rip(buf);
- }
- while (p!=NULL && (*buf=='\0' || *buf=='#'));
-
- if (p!=NULL)
- {
- vterm_printf(ftp->window->vt, ATTRIB_BOLD, "%s\r\n", buf);
- if (!cmdparse(ftpcmds, buf, ftp->window))
- return 1;
- else
- {
- vterm_printf(ftp->window->vt, ATTRIB_BOLD, "Error, Batch file closed.\r\n");
- fclose(ftp->batch);
- ftp->batch = NULL;
- }
- }
- else
- {
- vterm_printf(ftp->window->vt, ATTRIB_BOLD, "Batch completed.\r\n");
- fclose(ftp->batch);
- ftp->batch = NULL;
- }
- return 0;
- }
-
- void ftp_mpcleanup(struct ftp *ftp)
- {
- int i;
-
- ftp->margp = 0;
-
- if (ftp->margv!=NULL)
- {
- for (i=0; ftp->margv[i]!=NULL; i++)
- free(ftp->margv[i]);
- free(ftp->margv);
- ftp->margv = NULL;
- }
-
- if (ftp->mfp!=NULL)
- {
- fclose(ftp->mfp);
- ftp->mfp = NULL;
- }
-
- if (ftp->mtemp!=NULL)
- {
- remove(ftp->mtemp);
- free(ftp->mtemp);
- ftp->mtemp = NULL;
- }
-
- ftp->mpstate = FTPM_IDLE;
- }
-
-
- static int domget(int argc, char **argv)
- {
- int i;
- struct ftp *ftp;
-
- if ((ftp = current_ftp->cb.ftp) == NULLFTP)
- {
- cwprintf(ftp->window, notsess);
- return 1;
- }
-
- ftp_mpcleanup(ftp);
-
- /* must have at least one file */
- if (argc<2)
- {
- cwprintf(ftp->window, "No files requested.\r\n");
- return 1;
- }
-
- /* alloc for temp name and file list */
- if ((ftp->mtemp = strdup(tmpnam(NULL)), ftp->mtemp==NULL) ||
- (ftp->margv = (char **)malloc(argc*sizeof(char *)), ftp->margv==NULL))
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, nomemforop);
- return 1;
- }
-
- for (i=0; i<argc; i++)
- ftp->margv[i] = NULL;
-
- ftp->margp = 0;
-
- /* Copy file list */
- for (i=1; i<argc; i++)
- {
- if (ftp->margv[i-1] = strdup(argv[i]), ftp->margv[i-1]==NULL)
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, nomemforop);
- return 1;
- }
- }
-
- /* Initial open of temp list file */
- if (ftp->fp = fopen(ftp->mtemp, "w"), ftp->fp==NULL)
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, "Oops - temp file wont open\r\n");
- return 1;
- }
-
- /* start the ball rolling... */
- ftp->mpstate = FTPM_LISTING;
- mprocess(ftp);
- return 0;
- }
-
- static int mprocess(struct ftp *ftp)
- {
- char buf[256];
-
- if (ftp->mpstate==FTPM_IDLE)
- return 0;
-
- cwprintf(ftp->window, "mget> ");
-
- if (ftp->mpstate==FTPM_LISTING)
- {
- if (ftp->margv[ftp->margp]!=NULL)
- {
- if (ftp->fp==NULL)
- ftp->fp = fopen(ftp->mtemp, "a");
-
- if (ftp->fp==NULL)
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, "Temp file wont open - mget aborted\r\n");
- return 0;
- }
-
- ftp->state = RECEIVING_STATE;
- ftp->expected_size = 0;
- ftp->start_time = alarm_timenow () ;
- if ( ftp->type == IMAGE_TYPE )
- {
- ftp->type = IMAGE_PENDING ;
- sndftpmsg(ftp,"TYPE A\r\n");
- }
- ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
- /* Generate the command to start the transfer */
- sndftpmsg(ftp,"NLST %s\r\n",ftp->margv[ftp->margp++]);
- return 1;
- }
- else
- {
- ftp->mpstate = FTPM_GETFILES;
- if (ftp->mfp = fopen(ftp->mtemp, "r"), ftp->mtemp==NULL)
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, "Temp file wont open - mget aborted\r\n");
- return 0;
- }
- }
- }
-
- if (ftp->mpstate == FTPM_GETFILES)
- {
- strcpy(buf, "get ");
-
- if (fgets(buf+4, 256, ftp->mfp)!=NULL)
- {
- cwprintf(ftp->window, "%s\r\n", buf);
- if (!cmdparse(ftpcmds, buf, ftp->window))
- return 1;
- else
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, "Error, Batch file closed.\r\n");
- }
- }
- else
- {
- ftp_mpcleanup(ftp);
- cwprintf(ftp->window, "MGet completed.\r\n");
- }
- return 0;
- }
-
- return 0;
- }
-