home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / FTP / c / ftpcli < prev    next >
Encoding:
Text File  |  1995-02-02  |  37.2 KB  |  1,625 lines

  1. /* FTP client (interactive user) code */
  2. #define LINELEN         128     /* Length of command buffer */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include <stdarg.h>
  8. #include <ctype.h>
  9. #include "alarm.h"
  10. #include "global.h"
  11. #include "mbuf.h"
  12. #include "domain.h"
  13. #include "netuser.h"
  14. #include "icmp.h"
  15. #include "timer.h"
  16. #include "tcp.h"
  17. #include "ftp.h"
  18. #include "session.h"
  19. #include "cmdparse.h"
  20. #include "misc.h"
  21. #include "Terminal.h"
  22. #include "vterm.h"
  23. #include "bbc.h"
  24. #include "files.h"
  25. #include "pathent.h"
  26. #include "var.h"
  27.  
  28. extern varlist global_vars;
  29.  
  30. extern os_error *create_path(char *path, int size, int type);
  31. extern char *fttoa(int t);
  32.  
  33. extern struct session *current;
  34. struct session *current_ftp;
  35. extern char nospace[];
  36. extern char badhost[];
  37. static char notsess[]   = "Not an FTP session!\r\n";
  38. static char cantwrite[] = "Can't write %s\r\n";
  39. static char cantread[]  = "Can't read %s\r\n";
  40. static char nomemforop[] = "Insufficient memory for this operation\r\n";
  41.  
  42. static int  donothing(int, char **);
  43. static int  doftpquit(int, char **);
  44. static int  dowinclose(int, char **);
  45. static int  dowinopen(int, char **);
  46. static int  doftpcd(int, char **);
  47. static int  domkdir(int, char **);
  48. static int  dormdir(int, char **);
  49. static int  doascii(int, char **);
  50. static int  dobinary(int, char **);
  51. static int  dotype(int, char **);
  52. static int  doget(int, char **);
  53. static int  doreget(int, char **);
  54. static int  domget(int, char **);
  55. static int  dobatch(int, char **);
  56. static int  dopath(int, char **);
  57. static int  doquote(int, char **);
  58. static int  doview(int, char **);
  59. static int  dohash(int, char **);
  60. static int  dolist(int, char **);
  61. static int  dols(int, char **);
  62. static int  doput(int, char **);
  63. static void doreply(struct ftp *);
  64. static void ftpsetup(struct ftp *, void (*)(), void (*)(), void (*)());
  65. static void ftpccs(struct tcb *, char, char);
  66. static void ftpcds(struct tcb *, char, char);
  67. static int  sndftpmsg(struct ftp *, char *, ...);
  68. static void prompt(struct ftp *ftp);
  69. static int batch_ftp(struct ftp *ftp);
  70. static int mprocess(struct ftp *ftp);
  71.  
  72. void ftp_mpcleanup(struct ftp *ftp);
  73.  
  74.  
  75. struct cmds ftpabort[] = {
  76.   "",             donothing,    0,    NULLCHAR,               NULLCHAR,
  77.   "abort",        doabort,      0,    NULLCHAR,               NULLCHAR,
  78.   "hash",         dohash,       2,    "hash lumpsize",        NULLCHAR,
  79.   NULLCHAR,       NULLFP,       0,    "Only valid command is \"abort\"", NULLCHAR,
  80. };
  81.  
  82. struct cmds ftpcmds[] = {
  83.   "",             donothing,    0,    NULLCHAR,               NULLCHAR,
  84.   "ascii",        doascii,      0,    NULLCHAR,               NULLCHAR,
  85.   "abort",        doabort,      0,    NULLCHAR,               NULLCHAR,
  86.   "binary",       dobinary,     0,    NULLCHAR,               NULLCHAR,
  87.   "cd",           doftpcd,      2,    "cd <directory>",       NULLCHAR,
  88.   "dir",          dolist,       0,    NULLCHAR,               NULLCHAR,
  89.   "list",         dolist,       0,    NULLCHAR,               NULLCHAR,
  90.   "get",          doget,        2,    "get remotefile <localfile>",  NULLCHAR,
  91.   "hash",         dohash,       2,    "hash lumpsize",        NULLCHAR,
  92.   "image",        dobinary,     0,    NULLCHAR,               NULLCHAR,
  93.   "ls",           dols,         0,    NULLCHAR,               NULLCHAR,
  94.   "mget",         domget,       2,    "mget <filelist>",      NULLCHAR,
  95.   "mkdir",        domkdir,      2,    "mkdir <directory>",    NULLCHAR,
  96.   "nlst",         dols,         0,    NULLCHAR,               NULLCHAR,
  97.   "path",         dopath,       0,    "path [<path process options>|off|default]", NULLCHAR,
  98.   "put",          doput,        2,    "put localfile <remotefile>",  NULLCHAR,
  99.   "quote",        doquote,      0,    "quote <command>", NULLCHAR,
  100.   "reget",        doreget,      2,    "reget remotefile <localfile>",  NULLCHAR,
  101.   "rmdir",        dormdir,      2,    "rmdir <directory>",    NULLCHAR,
  102.   "source",       dobatch,      0,    "source <ftp command file>", NULLCHAR,
  103.   "type",         dotype,       0,    NULLCHAR,               NULLCHAR,
  104.   "view",         doview,       1,    "view remotefile",      NULLCHAR,
  105.   "winclose",     dowinclose,   0,    "winclose",             NULLCHAR,
  106.   "winopen",      dowinopen,    0,    "winopen",              NULLCHAR,
  107.   "quit",         doftpquit,    0,    "quit",                 NULLCHAR,
  108.   "bye",          doftpquit,    0,    "bye",                  NULLCHAR,
  109.   NULLCHAR,       NULLFP,       0,    NULLCHAR,               NULLCHAR,
  110. };
  111.  
  112. /* Handle top-level FTP command */
  113. int doftp(int argc, char **argv)
  114. {
  115.   int used_args;
  116.   struct session *s;
  117.   struct ftp *ftp;
  118.   struct tcb *tcb;
  119.   struct socket lsocket,fsocket;
  120.  
  121.   lsocket.address = ip_addr;
  122.   lsocket.port = lport++;
  123.   if ((fsocket.address = resolve(argv[1])) == 0)
  124.   {
  125.     cwprintf(NULL, badhost,argv[1]);
  126.     return 1;
  127.   }
  128.  
  129.   if (argc<3)
  130.   {
  131.     fsocket.port = FTP_PORT;
  132.     used_args = 2;
  133.   }
  134.   else
  135.   {
  136.     if (*argv[2]!='\\')
  137.     {
  138.       fsocket.port = atoi(argv[2]);
  139.       used_args = 3;
  140.     }
  141.     else
  142.     {
  143.       fsocket.port = FTP_PORT;
  144.       used_args = 2;
  145.     }
  146.   }
  147.   /* Allocate a session control block */
  148.   if ((s = newsession()) == NULLSESSION)
  149.   {
  150.     cwprintf(NULL, "Too many sessions\r\n");
  151.     return 1;
  152.   }
  153.   if ((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  154.     strcpy(s->name,argv[1]);
  155.   s->type = FTP;
  156.   s->parse = (void(*)())ftpparse;
  157.  
  158.   /* Allocate an FTP control block */
  159.   if ((ftp = ftp_create(LINELEN)) == NULLFTP)
  160.   {
  161.     s->type = FREE;
  162.     cwprintf(NULL, nospace);
  163.     return 1;
  164.   }
  165.   ftp->window = Window_Open(s, "FTP", term_SIXTEEN | term_CARET);
  166.   vterm_parse(ftp->window->vt, argc-used_args, &argv[used_args]);
  167.   current = s;
  168.   ftp->state   = STARTUP_STATE;
  169.   s->cb.ftp    = ftp;     /* Downward link */
  170.   ftp->session = s;       /* Upward link */
  171.   s->window    = ftp->window;
  172.   ftp->session->echo = TRUE;
  173.  
  174.   /* Now open the control connection */
  175.   tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, 0, (void(*)())ftpccr, NULLVFP, (void(*)())ftpccs, 0,( char *)ftp);
  176.   ftp->control = tcb;
  177.   go(s);
  178.   return 0;
  179. }
  180.  
  181. /* Parse user FTP commands */
  182. void ftpparse(struct session *active, char *line, int16 len)
  183. {
  184.   struct mbuf *bp;
  185.   extern struct cmds cmds[];
  186.   if (active == NULL)
  187.     active = current;
  188.   current_ftp = active;
  189.  
  190.   /* direct '*' prefixed commands to main command window */
  191.   if (*line=='*')
  192.   {
  193.     cmdparse(cmds, line+1, NULL);
  194.     prompt(active->cb.ftp);
  195.     return;
  196.   }
  197.  
  198.   switch(active->cb.ftp->state)
  199.   {
  200.   case RECEIVING_STATE:
  201.   case SENDING_FILE_STATE:
  202.     /* The only command allowed in data transfer state is ABORT */
  203.     if (cmdparse(ftpabort, line, active->window) == -1)
  204.     {
  205.       cwprintf(active->window, "Transfer in progress; only ABORT is acceptable\r\n");
  206.     }
  207.     break;
  208.   case COMMAND_STATE:
  209.     /* Save it now because cmdparse modifies the original */
  210.     bp = qdata(line,len);
  211.     if (cmdparse(ftpcmds, line, active->window) == -1)
  212.     {
  213.       /* Send it direct */
  214.       if (bp != NULLBUF)
  215.         send_tcp(active->cb.ftp->control,bp);
  216.       else
  217.         cwprintf(active->window, nospace);
  218.     }
  219.     else
  220.     {
  221.       free_p(bp);
  222.     }
  223.     break;
  224.   case STARTUP_STATE:             /* Startup up autologin */
  225.     cwprintf(active->window, "Not connected yet, ignoring %s\r\n",line);
  226.     break;
  227.   case USER_STATE:                /* Got the user name */
  228.     line[len] = '\0';
  229.     sndftpmsg(active->cb.ftp,"USER %s",line);
  230.     break;
  231.   case PASS_STATE:                /* Got the password */
  232.     cooked();
  233.     active->raw = FALSE;
  234.         vterm_setflags(active->window->vt,
  235.            /* Clear */ VTSW_CHAT|VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO,
  236.            /* Set */   VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO );
  237.     line[len] = '\0';
  238.     sndftpmsg(active->cb.ftp,"PASS %s",line);
  239.     break;
  240.   }
  241. }
  242.  
  243. /* Handle null line to avoid trapping on first command in table */
  244. static int donothing(int argc, char **argv)
  245. {
  246.   argc = argc;
  247.   argv = argv;
  248.   return 0;
  249. }
  250.  
  251. static int dowinclose(int argc, char **argv)
  252. {
  253.   register struct ftp *ftp;
  254.  
  255.   argc = argc;
  256.   argv = argv;
  257.  
  258.   ftp = current_ftp->cb.ftp;
  259.   vterm_close(current_ftp->window->vt);
  260.   current_ftp->window->Flags.flags.closing = 1;
  261.   prompt(ftp);
  262.  
  263.   return 0;
  264. }
  265.  
  266. static int dowinopen(int argc, char **argv)
  267. {
  268.   register struct ftp *ftp;
  269.  
  270.   argc = argc;
  271.   argv = argv;
  272.  
  273.   ftp = current_ftp->cb.ftp;
  274.   vterm_open(current_ftp->window->vt);
  275.   current_ftp->window->Flags.flags.closing = 0;
  276.   prompt(ftp);
  277.  
  278.   return 0;
  279. }
  280.  
  281. static int doftpquit(int argc, char **argv)
  282. {
  283.   int a;
  284.   register struct ftp *ftp;
  285.  
  286.   argc = argc;
  287.  
  288.   ftp = current_ftp->cb.ftp;
  289.   a = sndftpmsg(ftp,"QUIT\r\n");
  290.   prompt(ftp);
  291.  
  292.   return a;
  293. }
  294.  
  295.  
  296. /* Translate 'cd' to 'cwd' for convenience */
  297. static int doftpcd(int argc, char **argv)
  298. {
  299.   register struct ftp *ftp;
  300.  
  301.   argc = argc;
  302.  
  303.   ftp = current_ftp->cb.ftp;
  304.   return sndftpmsg(ftp,"CWD %s\r\n",argv[1]);
  305. }
  306.  
  307. /* Translate 'mkdir' to 'xmkd' for convenience */
  308. static int domkdir(int argc, char **argv)
  309. {
  310.   register struct ftp *ftp;
  311.  
  312.   argc = argc;
  313.  
  314.   ftp = current_ftp->cb.ftp;
  315.   return sndftpmsg(ftp,"XMKD %s\r\n",argv[1]);
  316. }
  317.  
  318. static int dohash(int argc, char **argv)
  319. {
  320.   register struct ftp *ftp;
  321.  
  322.   argc = argc;
  323.  
  324.   ftp = current_ftp->cb.ftp;
  325.   ftp->hash = atoi(argv[1]);
  326.   ftp->last = 0;
  327.  
  328.   prompt(ftp);
  329.   return(0);
  330. }
  331.  
  332. /* Translate 'rmdir' to 'xrmd' for convenience */
  333. static int dormdir(int argc, char **argv)
  334. {
  335.   register struct ftp *ftp;
  336.  
  337.   argc = argc;
  338.  
  339.   ftp = current_ftp->cb.ftp;
  340.   return sndftpmsg(ftp,"XRMD %s\r\n",argv[1]);
  341. }
  342.  
  343. static int dobinary(int argc, char **argv)
  344. {
  345.   register struct ftp *ftp;
  346.  
  347.   argc = argc;
  348.   argv = argv;
  349.  
  350.   ftp = current_ftp->cb.ftp;
  351.   ftp->type = IMAGE_TYPE;
  352.   sndftpmsg(ftp,"TYPE I\r\n");
  353.  
  354.   return(0);
  355. }
  356.  
  357. static int doascii(int argc, char **argv)
  358. {
  359.   register struct ftp *ftp;
  360.  
  361.   argc = argc;
  362.   argv = argv;
  363.  
  364.   ftp = current_ftp->cb.ftp;
  365.   ftp->type = ASCII_TYPE;
  366.   sndftpmsg(ftp,"TYPE A\r\n");
  367.  
  368.   return(0);
  369. }
  370.  
  371. /* Handle "type" command from user */
  372. static int dotype(int argc, char **argv)
  373. {
  374.   register struct ftp *ftp;
  375.  
  376.   ftp = current_ftp->cb.ftp;
  377.   if (argc < 2)
  378.   {
  379.     switch(ftp->type)
  380.     {
  381.     case IMAGE_TYPE:
  382.       cwprintf(ftp->window, "Image\r\n");
  383.       break;
  384.     case ASCII_TYPE:
  385.       cwprintf(ftp->window, "Ascii\r\n");
  386.       break;
  387.     }
  388.     return 0;
  389.   }
  390.   switch(*argv[1])
  391.   {
  392.   case 'i':
  393.   case 'b':
  394.     ftp->type = IMAGE_TYPE;
  395.     sndftpmsg(ftp,"TYPE I\r\n");
  396.     break;
  397.   case 'a':
  398.     ftp->type = ASCII_TYPE;
  399.     sndftpmsg(ftp,"TYPE A\r\n");
  400.     break;
  401.   case 'l':
  402.     ftp->type = IMAGE_TYPE;
  403.     sndftpmsg(ftp,"TYPE L %s\r\n",argv[2]);
  404.     break;
  405.   default:
  406.     cwprintf(ftp->window, "Invalid type %s\r\n",argv[1]);
  407.     return 1;
  408.   }
  409.   return 0;
  410. }
  411.  
  412. /* Verbatim command to server */
  413. static int doquote(int argc, char **argv)
  414. {
  415.   char localname[256];
  416.   register struct ftp *ftp;
  417.  
  418.   ftp = current_ftp->cb.ftp;
  419.   if (ftp == NULLFTP)
  420.   {
  421.     cwprintf(ftp->window, notsess);
  422.     return 1;
  423.   }
  424.  
  425.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  426.     fclose(ftp->fp);
  427.   ftp->restart = 0;  
  428.  
  429.   ftp->fp = NULLFILE;
  430.  
  431.   if (argc < 3)
  432.   {
  433.     ftp->fp = stdout;
  434.   }
  435.   else
  436.   {
  437.     if (strchr(argv[2], '.'))
  438.       strcpy(localname, argv[2]);
  439.     else
  440.       sprintf(localname, "<ftp$dir>.%s", argv[2]);
  441.  
  442.     /* Set variable to name of most recent file */
  443.     var_create_string(global_vars, "ftp_list", 0, localname);
  444.  
  445.     if ((ftp->fp = fopen(localname, "w")), ftp->fp == NULLFILE)
  446.     {
  447.       cwprintf(ftp->window, cantwrite,argv[2]);
  448.       return 1;
  449.     }
  450.   }
  451.  
  452.   ftp->state = RECEIVING_STATE;
  453.   ftp->expected_size = 0;
  454.   ftp->start_time = alarm_timenow () ;
  455.     if ( ftp->type == IMAGE_TYPE )
  456.     {
  457.       ftp->type = IMAGE_PENDING ;
  458.       sndftpmsg(ftp,"TYPE A\r\n");
  459.     }
  460.   ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
  461.   /* Generate the command to start the transfer */
  462.   return sndftpmsg(ftp,"%s\r\n",argv[1]);
  463. }
  464.  
  465.  
  466. /* Set current path processing options */
  467. static int dopath(int argc, char **argv)
  468. {
  469.   int i, n;
  470.   struct ftp *ftp;
  471.   char opts[256];
  472.   char *p;
  473.   pathent_str *pe;
  474.  
  475.   ftp = current_ftp->cb.ftp;
  476.  
  477.   if (ftp == NULLFTP)
  478.   {
  479.     cwprintf(NULL, notsess);
  480.     return 1;
  481.   }
  482.  
  483.   if (argc>1)
  484.   {
  485.     if ((argc==2) && !strncmp(argv[1], "off", strlen(argv[1])))
  486.     {
  487.       delpathent(ftp->pathopts);
  488.       ftp->pathopts = PATH_OFF;
  489.     }
  490.     else if ((argc==2) && !strncmp(argv[1], "auto", strlen(argv[1])))
  491.     {
  492.       delpathent(ftp->pathopts);
  493.       ftp->pathopts = PATH_DEF;
  494.     }
  495.     else if ((argc==2) && !strncmp(argv[1], "type", strlen(argv[1])))
  496.     {
  497.       delpathent(ftp->pathopts);
  498.       ftp->pathopts = PATH_TYPE;
  499.     }
  500.     else
  501.     {
  502.       /* Reconstrunct original path command */
  503.       *opts = '$';
  504.       p = opts+1;
  505.       for (i=1; i<argc; i++)
  506.       {
  507.         n = sprintf(p, " %s", argv[i]);
  508.         p += n;
  509.       }
  510.       if (pe = getpathent(opts), pe!=NULL)
  511.       {
  512.         delpathent(ftp->pathopts);
  513.         ftp->pathopts = pe;
  514.       }
  515.       else
  516.       {
  517.         cwprintf(ftp->window, "Parse error in path options.\r\n");
  518.         prompt(ftp);
  519.         return 1;
  520.       }
  521.     }
  522.   }
  523.   else
  524.   {
  525.     if (ftp->pathopts == PATH_OFF)
  526.       cwprintf(ftp->window, "Path processing off\r\n");
  527.     else if (ftp->pathopts == PATH_DEF)
  528.       cwprintf(ftp->window, "Auto path processing by extension\r\n");
  529.     else
  530.       cwprintf(ftp->window, "Preset path processing\r\n");
  531.    /* show_pathent(ftp->pathopts); */
  532.   }
  533.  
  534.   prompt(ftp);
  535.   return 0;
  536. }
  537.  
  538. /* Start processing a batch file. */
  539. static int dobatch(int argc, char **argv)
  540. {
  541.   extern char scripts[];
  542.  
  543.   struct ftp *ftp;
  544.   char file[256];
  545.  
  546.   ftp = current_ftp->cb.ftp;
  547.  
  548.   if (ftp == NULLFTP)
  549.   {
  550.     cwprintf(NULL, notsess);
  551.     return 1;
  552.   }
  553.  
  554.   if (ftp->batch!=NULL)
  555.   {
  556.     cwprintf(ftp->window, "Batch allready in progress.\r\n");
  557.     return 1;
  558.   }
  559.  
  560.   if (argc<2)
  561.   {
  562.     cwprintf(ftp->window, "No batch in progress.\r\n");
  563.     return 0;
  564.   }
  565.  
  566.   if (strpbrk(argv[1], "@&%$:<>"))
  567.     sprintf(file, "%s", argv[1]);
  568.   else
  569.     sprintf(file, "%s.%s", scripts, argv[1]);
  570.  
  571.   if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
  572.     goto opened;
  573.  
  574.   sprintf(file, "%s%s", RESROOT, argv[1]);
  575.  
  576.   if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
  577.     goto opened;
  578.     
  579.   sprintf(file, "%s^.%s", RESROOT, argv[1]);
  580.  
  581.   if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
  582.     goto opened;
  583.     
  584.   sprintf(file, "@.%s", argv[1]);
  585.  
  586.   if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
  587.     goto opened;
  588.     
  589.   sprintf(file, "$.%s", argv[1]);
  590.  
  591.   if (ftp->batch = fopen(file, "r"), ftp->batch!=NULL)
  592.     goto opened;
  593.     
  594.   cwprintf(ftp->window, "Cant find batch file \"%s\".\r\n", argv[1]);
  595.   return 1;
  596.  
  597. opened:
  598.   prompt(ftp);
  599.   return 0;
  600. }
  601.  
  602. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  603. static int doget(int argc, char **argv)
  604. {
  605.   os_error *e;
  606.   char *remotename, *temp, *cp, localname[256];
  607.   register struct ftp *ftp;
  608.   char *mode;
  609.   int filetype = -1;
  610.  
  611.   ftp = current_ftp->cb.ftp;
  612.   if (ftp == NULLFTP)
  613.   {
  614.     cwprintf(NULL, notsess);
  615.     return 1;
  616.   }
  617.   remotename = argv[1];
  618.  
  619. /*
  620.   bbc_vdu(4);
  621.   bbc_vdu(26);
  622.   bbc_vdu(30);
  623. */
  624.   if (argc < 3)
  625.   {
  626.     if (ftp->pathopts==PATH_OFF ||
  627.         !pathmap(remotename, localname, &filetype, ftp->pathopts) ||
  628.         ftp->pathopts==PATH_TYPE)
  629.     {
  630.       temp = strdup(remotename);
  631.       cp = temp;
  632.       while (cp = strpbrk(cp, "\"[]|<>+=;,./\\"), cp != NULL)
  633.       {
  634.         if (*cp=='/' || *cp=='\\')
  635.           *cp++ = '.';
  636.         else if (*cp=='.')
  637.           *cp++ = '/';
  638.         else
  639.           *cp++ = '_';
  640.       }
  641. /*
  642.       if (strlen(temp) > 10)
  643.         temp[10] = '\0';
  644. */
  645.       sprintf(localname, "<FTP$dir>.%s", (*temp=='.')?temp+1:temp);
  646.       free(temp);
  647.     }
  648.     if (filetype<0)
  649.       filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
  650.   }
  651.   else
  652.   {
  653.     if (ftp->pathopts!=PATH_OFF)
  654.       pathmap(remotename, localname, &filetype, PATH_TYPE);
  655.  
  656.     if (strpbrk(argv[2], "$&%<>:"))
  657.       strcpy(localname, argv[2]);
  658.     else
  659.       sprintf(localname, "<FTP$Dir>.%s", argv[2]);
  660.     if (filetype<0)
  661.       filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
  662.   }
  663. /*
  664.   printf("file: %s, type: %.3x\n", localname, filetype);
  665. */
  666.   cwprintf(ftp->window,"Opening %s (%s)\r\n", localname, fttoa(filetype));
  667.  
  668.   /* Set variable to name of most recent file */
  669.   var_create_string(global_vars, "ftp_data", 0, localname);
  670.  
  671.   /* creates the file, ensuring a path is present */
  672.   if (e = create_path(localname, 0, filetype), e!=NULL)
  673.   {
  674.     cwprintf(ftp->window,"Cant create local file - %s\n", e->errmess);
  675.     return 1;
  676.   }
  677.  
  678.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  679.     fclose(ftp->fp);
  680.   ftp->restart = 0;  
  681.  
  682.   ftp->fp = NULLFILE;
  683.  
  684.   if (ftp->type == IMAGE_PENDING)
  685.   {
  686.     ftp->type = IMAGE_TYPE ;
  687.     sndftpmsg(ftp,"TYPE I\r\n");
  688.   }
  689.  
  690.   if (ftp->type == IMAGE_TYPE)
  691.     mode = binmode[WRITE_BINARY];
  692.   else
  693.     mode = "w";
  694.  
  695.   if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
  696.   {
  697.     cwprintf(ftp->window, cantwrite, localname);
  698.     return 1;
  699.   }
  700.   if (ftp->type == IMAGE_TYPE)
  701.     setvbuf(ftp->fp, NULL, _IOFBF, 16384);
  702.   
  703.   ftp->filetype = filetype;
  704.   ftp->last = 0;
  705.   ftp->state = RECEIVING_STATE;
  706.   ftp->expected_size = 0;
  707.   ftp->start_time = alarm_timenow () ;
  708.   ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
  709.  
  710.   /* Generate the command to start the transfer */
  711.   return sndftpmsg(ftp,"RETR %s\r\n",remotename);
  712. }
  713.  
  714. static int doreget(int argc, char **argv)
  715. {
  716.   os_error *e;
  717.   char *remotename, *temp, *cp, localname[256];
  718.   register struct ftp *ftp;
  719.   char *mode;
  720.   int filetype = -1;
  721.  
  722.   ftp = current_ftp->cb.ftp;
  723.   if (ftp == NULLFTP)
  724.   {
  725.     cwprintf(NULL, notsess);
  726.     return 1;
  727.   }
  728.   remotename = argv[1];
  729.  
  730. /*
  731.   bbc_vdu(4);
  732.   bbc_vdu(26);
  733.   bbc_vdu(30);
  734. */
  735.   if (argc < 3)
  736.   {
  737.     if (ftp->pathopts==PATH_OFF ||
  738.         !pathmap(remotename, localname, &filetype, ftp->pathopts) ||
  739.         ftp->pathopts==PATH_TYPE)
  740.     {
  741.       temp = strdup(remotename);
  742.       cp = temp;
  743.       while (cp = strpbrk(cp, "\"[]|<>+=;,./\\"), cp != NULL)
  744.       {
  745.         if (*cp=='/' || *cp=='\\')
  746.           *cp++ = '.';
  747.         else if (*cp=='.')
  748.           *cp++ = '/';
  749.         else
  750.           *cp++ = '_';
  751.       }
  752. /*
  753.       if (strlen(temp) > 10)
  754.         temp[10] = '\0';
  755. */
  756.       sprintf(localname, "<FTP$dir>.%s", (*temp=='.')?temp+1:temp);
  757.       free(temp);
  758.     }
  759.     if (filetype<0)
  760.       filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
  761.   }
  762.   else
  763.   {
  764.     if (ftp->pathopts!=PATH_OFF)
  765.       pathmap(remotename, localname, &filetype, PATH_TYPE);
  766.  
  767.     if (strpbrk(argv[2], "$&%<>:"))
  768.       strcpy(localname, argv[2]);
  769.     else
  770.       sprintf(localname, "<FTP$Dir>.%s", argv[2]);
  771.     if (filetype<0)
  772.       filetype = (ftp->type == IMAGE_TYPE)?0xffd:0xfff;
  773.   }
  774. /*
  775.   printf("file: %s, type: %.3x\n", localname, filetype);
  776. */
  777.   cwprintf(ftp->window,"Opening %s (%s)\r\n", localname, fttoa(filetype));
  778.  
  779.   /* Set variable to name of most recent file */
  780.   var_create_string(global_vars, "ftp_data", 0, localname);
  781.  
  782.   /* creates the file, ensuring a path is present */
  783.   if (e = create_path(localname, 0, filetype), e!=NULL)
  784.   {
  785.     cwprintf(ftp->window,"Cant create local file - %s\n", e->errmess);
  786.     return 1;
  787.   }
  788.  
  789.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  790.     fclose(ftp->fp);
  791.  
  792.   ftp->fp = NULLFILE;
  793.  
  794.   if (ftp->type == IMAGE_PENDING)
  795.   {
  796.     ftp->type = IMAGE_TYPE ;
  797.     sndftpmsg(ftp,"TYPE I\r\n");
  798.   }
  799.  
  800.   if (ftp->type == IMAGE_TYPE)
  801.     mode = "ab";
  802.   else
  803.     mode = "a";
  804.  
  805.   if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
  806.   {
  807.     cwprintf(ftp->window, cantwrite, localname);
  808.     return 1;
  809.   }
  810.   if (ftp->type == IMAGE_TYPE)
  811.     setvbuf(ftp->fp, NULL, _IOFBF, 16384);
  812.  
  813.   ftp->restart = ftell(ftp->fp);
  814.   
  815.   ftp->filetype = filetype;
  816.   ftp->last = 0;
  817.   ftp->state = RECEIVING_STATE;
  818.   ftp->expected_size = 0;
  819.   ftp->start_time = alarm_timenow () ;
  820.   ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
  821.  
  822.   /* Generate the commands to start the transfer */
  823.   sndftpmsg(ftp,"REST %ld\r\n",ftp->restart);
  824.   return sndftpmsg(ftp,"RETR %s\r\n",remotename);
  825. }
  826.  
  827. /* Start receive transfer. Syntax: view <remote name> */
  828. static int doview(int argc, char **argv)
  829. {
  830.   char *remotename;
  831.   register struct ftp *ftp;
  832.  
  833.   ftp = current_ftp->cb.ftp;
  834.   if (ftp == NULLFTP)
  835.   {
  836.     cwprintf(ftp->window, notsess);
  837.     return 1;
  838.   }
  839.   remotename = argv[1];
  840.  
  841.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  842.     fclose(ftp->fp);
  843.   ftp->fp = NULLFILE;
  844.   ftp->restart = 0;  
  845.  
  846.   if (ftp->type == IMAGE_PENDING)
  847.   {
  848.     ftp->type = IMAGE_TYPE ;
  849.     sndftpmsg(ftp,"TYPE I\r\n");
  850.   }
  851.  
  852.   ftp->fp = stdout ;
  853.   ftp->last = 0;
  854.   ftp->state = RECEIVING_STATE;
  855.   ftp->expected_size = 0;
  856.   ftp->start_time = alarm_timenow () ;
  857.   ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
  858.  
  859.   /* Generate the command to start the transfer */
  860.   return sndftpmsg(ftp,"RETR %s\r\n",remotename);
  861. }
  862.  
  863. /* List remote directory. Syntax: dir <remote directory/file> [<local name>] */
  864. static int dolist(int argc, char **argv)
  865. {
  866.   char localname[256];
  867.   register struct ftp *ftp;
  868.  
  869.   ftp = current_ftp->cb.ftp;
  870.   if (ftp == NULLFTP)
  871.   {
  872.     cwprintf(ftp->window, notsess);
  873.     return 1;
  874.   }
  875.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  876.     fclose(ftp->fp);
  877.   ftp->fp = NULLFILE;
  878.   ftp->restart = 0;  
  879.  
  880.   if (argc < 3)
  881.   {
  882.     ftp->fp = stdout;
  883.   }
  884.   else
  885.   {
  886.     if (strchr(argv[2], '.'))
  887.       strcpy(localname, argv[2]);
  888.     else
  889.       sprintf(localname, "<ftp$dir>.%s", argv[2]);
  890.  
  891.     /* Set variable to name of most recent file */
  892.     var_create_string(global_vars, "ftp_list", 0, localname);
  893.  
  894.     if ((ftp->fp = fopen(localname, "w")), ftp->fp == NULLFILE)
  895.     {
  896.       cwprintf(ftp->window, cantwrite,argv[2]);
  897.       return 1;
  898.     }
  899.   }
  900.   ftp->state = RECEIVING_STATE;
  901.   ftp->expected_size = 0;
  902.   ftp->start_time = alarm_timenow () ;
  903.   ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
  904.   /* Generate the command to start the transfer
  905.      It's done this way to avoid confusing the 4.2 FTP server
  906.      if there's no argument */
  907.   if (argc > 1)
  908.   {
  909.     if ( ftp->type == IMAGE_TYPE )
  910.     {
  911.       ftp->type = IMAGE_PENDING ;
  912.       sndftpmsg(ftp,"TYPE A\r\n");
  913.     }
  914.     return sndftpmsg(ftp,"LIST %s\r\n",argv[1]);
  915.   }
  916.   else
  917.   {
  918.     if ( ftp->type == IMAGE_TYPE )
  919.     {
  920.       ftp->type = IMAGE_PENDING ;
  921.       sndftpmsg(ftp,"TYPE A\r\n");
  922.     }
  923.     return sndftpmsg(ftp,"LIST\r\n","");
  924.   }
  925. }
  926. /* Abbreviated (name only) list of remote directory.
  927.  * Syntax: ls <remote directory/file> [<local name>]
  928.  */
  929. static int dols(int argc, char **argv)
  930. {
  931.   char localname[256];
  932.   register struct ftp *ftp;
  933.  
  934.   ftp = current_ftp->cb.ftp;
  935.   if (ftp == NULLFTP)
  936.   {
  937.     cwprintf(ftp->window, notsess);
  938.     return 1;
  939.   }
  940.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  941.     fclose(ftp->fp);
  942.   ftp->fp = NULLFILE;
  943.   ftp->restart = 0;  
  944.  
  945.   if (argc < 3)
  946.   {
  947.     ftp->fp = stdout;
  948.   }
  949.   else
  950.   {
  951.     if (strchr(argv[2], '.'))
  952.       strcpy(localname, argv[2]);
  953.     else
  954.       sprintf(localname, "<ftp$dir>.%s", argv[2]);
  955.  
  956.     /* Set variable to name of most recent file */
  957.     var_create_string(global_vars, "ftp_list", 0, localname);
  958.  
  959.     if ((ftp->fp = fopen(localname, "w")), ftp->fp == NULLFILE)
  960.     {
  961.       cwprintf(ftp->window, cantwrite,argv[2]);
  962.       return 1;
  963.     }
  964.   }
  965.   ftp->state = RECEIVING_STATE;
  966.   ftp->expected_size = 0;
  967.   ftp->start_time = alarm_timenow () ;
  968.     if ( ftp->type == IMAGE_TYPE )
  969.     {
  970.       ftp->type = IMAGE_PENDING ;
  971.       sndftpmsg(ftp,"TYPE A\r\n");
  972.     }
  973.   ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
  974.   /* Generate the command to start the transfer */
  975.   if (argc > 1)
  976.   {
  977.     return sndftpmsg(ftp,"NLST %s\r\n",argv[1]);
  978.   }
  979.   else
  980.   {
  981.     return sndftpmsg(ftp,"NLST\r\n","");
  982.   }
  983. }
  984. /* Start transmit. Syntax: put <local name> [<remote name>] */
  985. static int doput(int argc, char **argv)
  986. {
  987.   char *remotename,*localname;
  988.   char *mode;
  989.   struct ftp *ftp;
  990.  
  991.   if ((ftp = current_ftp->cb.ftp) == NULLFTP)
  992.   {
  993.     cwprintf(ftp->window, notsess);
  994.     return 1;
  995.   }
  996.   localname = argv[1];
  997.   if (argc < 3)
  998.     remotename = localname;
  999.   else
  1000.       remotename = argv[2];
  1001.  
  1002.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  1003.     fclose(ftp->fp);
  1004.   ftp->restart = 0;  
  1005.  
  1006.   if (ftp->type == IMAGE_PENDING)
  1007.   {
  1008.     ftp->type = IMAGE_TYPE ;
  1009.     sndftpmsg(ftp,"TYPE I\r\n");
  1010.   }
  1011.  
  1012.   if (ftp->type == IMAGE_TYPE)
  1013.     mode = binmode[READ_BINARY];
  1014.   else
  1015.     mode = "r";
  1016.  
  1017.   if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
  1018.   {
  1019.     cwprintf(ftp->window, cantread,localname);
  1020.     return 1;
  1021.   }
  1022.   fseek(ftp->fp,0,SEEK_END);
  1023.   ftp->expected_size = ftell(ftp->fp);
  1024.   fseek(ftp->fp,0,SEEK_SET);
  1025.   ftp->last = 0;
  1026.   ftp->state = SENDING_FILE_STATE;
  1027.   ftp->start_time = alarm_timenow () ;
  1028.   ftpsetup(ftp, NULLVFP, (void(*)())ftpdt, (void(*)())ftpcds);
  1029.  
  1030.   /* Generate the command to start the transfer */
  1031.   return sndftpmsg(ftp,"STOR %s\r\n",remotename);
  1032. }
  1033. /* Abort a GET or PUT operation in progress. Note: this will leave
  1034.  * the partial file on the local or remote system
  1035.  */
  1036. int doabort(int argc, char **argv)
  1037. {
  1038.   register struct ftp *ftp;
  1039.  
  1040.   argc = argc;
  1041.   argv = argv;
  1042.  
  1043.   ftp = current_ftp->cb.ftp;
  1044.  
  1045.   /* Close the local file */
  1046.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  1047.     fclose(ftp->fp);
  1048.   ftp->fp = NULLFILE;
  1049.  
  1050.   ftp->restart = 0;
  1051.  
  1052.   ftp_mpcleanup(ftp);
  1053.  
  1054.   if (ftp->batch)
  1055.   {
  1056.     cwprintf(ftp->window, "Batch file closed\r\n");
  1057.     fclose(ftp->batch);
  1058.     ftp->batch = NULL;
  1059.   }
  1060.  
  1061.   switch(ftp->state)
  1062.   {
  1063.   case SENDING_FILE_STATE:
  1064.     /* Send a premature EOF.
  1065.        Unfortunately we can't just reset the connection
  1066.        since the remote side might end up waiting forever
  1067.        for us to send something. */
  1068.     close_tcp(ftp->data);
  1069.     cwprintf(ftp->window, "Put aborted\r\n");
  1070.     break;
  1071.   case RECEIVING_STATE:
  1072.     /* Just exterminate the data channel TCB; this will
  1073.                      * generate a RST on the next data packet which will
  1074.                      * abort the sender
  1075.                      */
  1076.     del_tcp(ftp->data);
  1077.     ftp->data = NULLTCB;
  1078.     cwprintf(ftp->window, "Get aborted\r\n");
  1079.     break;
  1080.   }
  1081.  
  1082.   ftp->state = COMMAND_STATE;
  1083.   prompt(ftp);
  1084.   return 0;
  1085. }
  1086. /* create data port, and send PORT message */
  1087. static void ftpsetup(struct ftp *ftp, void (*recv)(),
  1088.                      void (*send)(), void (*state)())
  1089. {
  1090.   struct socket lsocket;
  1091.   struct mbuf *bp;
  1092.  
  1093.   lsocket.address = ip_addr;
  1094.   lsocket.port = lport++;
  1095.  
  1096.   /* Compose and send PORT a,a,a,a,p,p message */
  1097.  
  1098.   if ((bp = alloc_mbuf(35)) == NULLBUF)
  1099.   {   /* 5 more than worst case */
  1100.     cwprintf(ftp->window, nospace);
  1101.     return;
  1102.   }
  1103.   /* I know, this looks gross, but it works! */
  1104.   sprintf(bp->data,"PORT %u,%u,%u,%u,%u,%u\r\n",
  1105.           hibyte(hiword(lsocket.address)),
  1106.           lobyte(hiword(lsocket.address)),
  1107.           hibyte(loword(lsocket.address)),
  1108.           lobyte(loword(lsocket.address)),
  1109.           hibyte(lsocket.port),
  1110.           lobyte(lsocket.port) );
  1111.   bp->cnt = strlen(bp->data);
  1112.   send_tcp(ftp->control,bp);
  1113.  
  1114.   /* Post a listen on the data connection */
  1115.   ftp->data = open_tcp(&lsocket,NULLSOCK,TCP_PASSIVE,0,
  1116.   recv,send,state,0,(char *)ftp);
  1117. }
  1118.  
  1119. /* FTP Client Control channel Receiver upcall routine */
  1120. void ftpccr(register struct tcb *tcb, int16 cnt)
  1121. {
  1122.   extern int ttyflow;
  1123.   struct mbuf *bp;
  1124.   struct ftp *ftp;
  1125.   char c;
  1126.  
  1127.   if ((ftp = (struct ftp *)tcb->user) == NULLFTP)
  1128.   {
  1129.     /* Unknown connection; kill it */
  1130.     close_tcp(tcb);
  1131.     return;
  1132.   }
  1133.   /* Hold output if we're not the current session */
  1134.   if (ftp->window == NULL && (mode != CONV_MODE || current == NULLSESSION
  1135.       || ttyflow == 0 || current->cb.ftp != ftp))
  1136.     return;
  1137.  
  1138.   if (recv_tcp(tcb,&bp,cnt) > 0)
  1139.   {
  1140.     while(pullone(&bp,&c) == 1)
  1141.   {
  1142.       switch(c)
  1143.   {
  1144.       case '\n':      /* Complete line; process it */
  1145.  
  1146.         ftp->buf[ftp->cnt] = '\0';
  1147.         doreply(ftp);
  1148.         ftp->cnt = 0;
  1149.         break;
  1150.       default:
  1151.         if (ftp->cnt != LINELEN-1)
  1152.           ftp->buf[ftp->cnt++] = c;
  1153.         break;
  1154.       }
  1155.     }
  1156.   }
  1157. }
  1158.  
  1159. int extract_line_number ( char * l )
  1160. {
  1161.   int i = 0 , c ;
  1162.  
  1163.   for ( c = 0 ; c < 3 ; c ++ )
  1164.   {
  1165.     if ( isdigit ( l [c] ) )
  1166.     {
  1167.       i = i * 10 + ( l [c] - '0' ) ;
  1168.     }
  1169.     else
  1170.     {
  1171.       c = 3 ;
  1172.     }
  1173.   }
  1174.   return ( i ) ;
  1175. }
  1176.  
  1177. /* Process replies from the server */
  1178. static void doreply(register struct ftp *ftp)
  1179. {
  1180.   char **s;
  1181.  
  1182.   cwprintf(ftp->window, "%s\r\n",ftp->buf);
  1183.  
  1184.   if (ftp->cnt < 3)
  1185.     return;
  1186.  
  1187.   if ( ftp->state == CONTINUATION_STATE )
  1188.   {
  1189.     if ( ftp->continue_val == extract_line_number ( ftp->buf ) )
  1190.     {
  1191.       ftp->state = ftp->last_state ;
  1192.     }
  1193.     else
  1194.     {
  1195.       return;
  1196.     }
  1197.   }
  1198.  
  1199.   if (ftp->buf[3] == '-')
  1200.   {
  1201.     ftp->last_state = ftp->state ;
  1202.     ftp->state = CONTINUATION_STATE ;
  1203.     ftp->continue_val = extract_line_number ( ftp->buf ) ;
  1204.     return;
  1205.   }
  1206.  
  1207.   switch(ftp->state)
  1208.   {
  1209.   case SENDING_FILE_STATE:
  1210.   case RECEIVING_STATE:
  1211.     if (ftp->buf[0] == '5')
  1212.       doabort(0, s);
  1213.     else if ( extract_line_number ( ftp->buf ) == 150 )
  1214.     {
  1215.       /* Opening message - see if we can find a file size... */
  1216.       char *s = strchr(ftp->buf , '(');
  1217.  
  1218.       if (sscanf(s, "(%lu bytes)", &ftp->expected_size) < 1)
  1219.       {
  1220.         ftp->expected_size = 0;
  1221.       }
  1222.     }
  1223.     break;
  1224.   case STARTUP_STATE:
  1225.     if (strncmp(ftp->buf, "220", 3) == 0)
  1226.   {
  1227.       ftp->state = USER_STATE;
  1228.       cwprintf(ftp->window, "Enter user name: ");
  1229.     }
  1230.     else ftp->state = COMMAND_STATE;
  1231.     break;
  1232.   case USER_STATE:
  1233.     if (strncmp(ftp->buf, "331", 3) == 0)
  1234.     {
  1235.       ftp->state = PASS_STATE;
  1236.       noecho();
  1237.       ftp->session->echo = FALSE;
  1238.       cwprintf(ftp->window, "Password: ");
  1239.       vterm_setflags(ftp->window->vt,VTSW_ECHO,0);
  1240.     }
  1241.     else ftp->state = COMMAND_STATE;
  1242.     break;
  1243.   case PASS_STATE:
  1244.     echo();
  1245.     ftp->session->echo = TRUE;
  1246.     ftp->state = COMMAND_STATE;
  1247.     vterm_setflags(ftp->window->vt,VTSW_ECHO,VTSW_ECHO);
  1248.   case COMMAND_STATE:
  1249.     prompt(ftp);
  1250.     break;
  1251.   }
  1252. }
  1253.  
  1254. /* FTP Client Control channel State change upcall routine */
  1255. static void ftpccs(register struct tcb *tcb, char old, char new)
  1256. {
  1257.   extern int ttyflow;
  1258.   struct ftp *ftp;
  1259.   char notify = 0;
  1260.   extern char *tcpstates[];
  1261.   extern char *reasons[];
  1262.   extern char *unreach[];
  1263.   extern char *exceed[];
  1264.  
  1265.   old = old;
  1266.  
  1267.   /* Can't add a check for unknown connection here, it would loop
  1268.            * on a close upcall! We're just careful later on.
  1269.            */
  1270.   ftp = (struct ftp *)tcb->user;
  1271.  
  1272.   if (ftp->window || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
  1273.     notify = 1;
  1274.  
  1275.   switch(new)
  1276.   {
  1277.   case CLOSE_WAIT:
  1278.     if (notify)
  1279.       cwprintf(ftp->window, "%s\r\n",tcpstates[new]);
  1280.     close_tcp(tcb);
  1281.     break;
  1282.   case CLOSED:    /* heh heh */
  1283.     if (notify)
  1284.     {
  1285.       cwprintf(ftp->window, "%s (%s",tcpstates[new],reasons[tcb->reason]);
  1286.       if (tcb->reason == NETWORK)
  1287.       {
  1288.         switch(tcb->type)
  1289.         {
  1290.         case DEST_UNREACH:
  1291.           cwprintf(ftp->window, ": %s unreachable",unreach[tcb->code]);
  1292.           break;
  1293.         case TIME_EXCEED:
  1294.           cwprintf(ftp->window, ": %s time exceeded",exceed[tcb->code]);
  1295.           break;
  1296.         }
  1297.       }
  1298.       cwprintf(ftp->window, ")\r\n");
  1299.       cmdmode();
  1300.     }
  1301.     del_tcp(tcb);
  1302.     if (ftp != NULLFTP)
  1303.     {
  1304.       if (ftp->window)
  1305.       {
  1306.         ftp->window->Attr = ATTR_REVERSE;
  1307.         ftp->window->Flags.flags.dont_destroy = FALSE;
  1308.         ftp->window->Session = NULL;
  1309.         Window_CloseDown(ftp->window);
  1310.       }
  1311.       ftp_delete(ftp);
  1312.     }
  1313.     break;
  1314.   default:
  1315.     if (notify)
  1316.       cwprintf(ftp->window, "%s\r\n",tcpstates[new]);
  1317.     break;
  1318.   }
  1319. }
  1320. /* FTP Client Data channel State change upcall handler */
  1321. static void ftpcds(struct tcb *tcb, char old, char new)
  1322. {
  1323.   extern int ttyflow;
  1324.   struct ftp *ftp;
  1325.  
  1326.   old = old;
  1327.  
  1328.   if ((ftp = (struct ftp *)tcb->user) == NULLFTP)
  1329.   {
  1330.     /* Unknown connection, kill it */
  1331.     close_tcp(tcb);
  1332.     return;
  1333.   }
  1334.   switch(new)
  1335.   {
  1336.   case FINWAIT2:
  1337.   case TIME_WAIT:
  1338.     if (ftp->state == SENDING_FILE_STATE)
  1339.     {
  1340.       /* We've received an ack of our FIN, so
  1341.                                * return to command mode
  1342.                                */
  1343.       ftp->state = COMMAND_STATE;
  1344.       if (ftp->window != NULL || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
  1345.       {
  1346.         int  a = alarm_timedifference(ftp->start_time, alarm_timenow()) / 100;
  1347.         long b = tcb->snd.una - tcb->iss - 2;
  1348.  
  1349.         if (ftp->hash > 0)
  1350.           cwputchar(ftp->window, '\n');
  1351.         if (a == 0)
  1352.           a++;
  1353.         cwprintf(ftp->window, "Put complete, %lu bytes sent (%lu cps)\r\n", b, b/a);
  1354.         prompt(ftp);
  1355.       }
  1356.     }
  1357.     break;
  1358.   case CLOSE_WAIT:
  1359.     close_tcp(tcb);
  1360.     if (ftp->state == RECEIVING_STATE)
  1361.     {
  1362.       /* End of file received on incoming file */
  1363.       if (ftp->fp != stdout)
  1364.         fclose(ftp->fp);
  1365.       ftp->fp = NULLFILE;
  1366.       ftp->state = COMMAND_STATE;
  1367.       if (ftp->window != NULL || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
  1368.       {
  1369.         int  a = alarm_timedifference(ftp->start_time, alarm_timenow()) / 100;
  1370.         long b = tcb->rcv.nxt - tcb->irs - 2;
  1371.  
  1372.         if ( ftp->hash > 0 )
  1373.           cwputchar(ftp->window, '\n');
  1374.         if (a == 0)
  1375.           a++;
  1376.         if (ftp->restart)
  1377.           cwprintf(ftp->window, "Get complete, remaining %lu of %lu bytes received (%lu cps)\r\n",
  1378.                    b, b+ftp->restart, b/a);
  1379.         else
  1380.           cwprintf(ftp->window, "Get complete, %lu bytes received (%lu cps)\r\n", b, b/a);
  1381.         prompt(ftp);
  1382.       }
  1383.       ftp->restart = 0;
  1384.     }
  1385.     break;
  1386.   case CLOSED:
  1387.     ftp->data = NULLTCB;
  1388.     del_tcp(tcb);
  1389.     break;
  1390.   }
  1391. }
  1392.  
  1393. /* Send a message on the control channel */
  1394. static int sndftpmsg(struct ftp *ftp, char *fmt, ...)
  1395. {
  1396.   va_list argptr;
  1397.   struct mbuf *bp;
  1398.   int16 len;
  1399.  
  1400.   va_start(argptr,fmt);
  1401.   len = strlen(fmt) + strlen(va_arg(argptr,char *)) + 10;   /* fudge factor */
  1402.   va_end(argptr);
  1403.   if ((bp = alloc_mbuf(len)) == NULLBUF)
  1404.   {
  1405.     cwprintf(ftp->window, nospace);
  1406.     return 1;
  1407.   }
  1408.   va_start(argptr,fmt);
  1409.   vsprintf(bp->data,fmt,argptr);
  1410.   va_end(argptr);
  1411.   bp->cnt = strlen(bp->data);
  1412.   send_tcp(ftp->control,bp);
  1413.   return 0;
  1414. }
  1415.  
  1416. static void prompt(struct ftp *ftp)
  1417. {
  1418.   if (ftp->state==RECEIVING_STATE || ftp->state==SENDING_FILE_STATE)
  1419.     cwprintf(ftp->window, "%s- ",(ftp->batch)?"batch":(ftp->mpstate==FTPM_IDLE)?"ftp":"mget");
  1420.   else if (!mprocess(ftp) && !batch_ftp(ftp))
  1421.     cwprintf(ftp->window, "ftp> ");
  1422. }
  1423.  
  1424. static int batch_ftp(struct ftp *ftp)
  1425. {
  1426.   char *p;
  1427.   char buf[256];
  1428.  
  1429.   if (!ftp->batch)
  1430.     return 0;
  1431.  
  1432.   cwprintf(ftp->window, "batch> ");
  1433.  
  1434.   do
  1435.   {
  1436.     p = fgets(buf, 256, ftp->batch);
  1437.     rip(buf);
  1438.   }
  1439.   while (p!=NULL && (*buf=='\0' || *buf=='#'));
  1440.  
  1441.   if (p!=NULL)
  1442.   {
  1443.     vterm_printf(ftp->window->vt, ATTRIB_BOLD, "%s\r\n", buf);
  1444.     if (!cmdparse(ftpcmds, buf, ftp->window))
  1445.       return 1;
  1446.     else
  1447.     {
  1448.       vterm_printf(ftp->window->vt, ATTRIB_BOLD, "Error, Batch file closed.\r\n");
  1449.       fclose(ftp->batch);
  1450.       ftp->batch = NULL;
  1451.     }
  1452.   }
  1453.   else
  1454.   {
  1455.     vterm_printf(ftp->window->vt, ATTRIB_BOLD, "Batch completed.\r\n");
  1456.     fclose(ftp->batch);
  1457.     ftp->batch = NULL;
  1458.   }  
  1459.   return 0;
  1460. }
  1461.  
  1462. void ftp_mpcleanup(struct ftp *ftp)
  1463. {
  1464.   int i;
  1465.   
  1466.   ftp->margp = 0;
  1467.  
  1468.   if (ftp->margv!=NULL)
  1469.   {
  1470.     for (i=0; ftp->margv[i]!=NULL; i++)
  1471.       free(ftp->margv[i]);
  1472.     free(ftp->margv);
  1473.     ftp->margv = NULL;
  1474.   }
  1475.  
  1476.   if (ftp->mfp!=NULL)
  1477.   {
  1478.     fclose(ftp->mfp);
  1479.     ftp->mfp = NULL;
  1480.   }
  1481.  
  1482.   if (ftp->mtemp!=NULL)
  1483.   {
  1484.     remove(ftp->mtemp);
  1485.     free(ftp->mtemp);
  1486.     ftp->mtemp = NULL;
  1487.   }
  1488.  
  1489.   ftp->mpstate = FTPM_IDLE;
  1490. }
  1491.  
  1492.  
  1493. static int domget(int argc, char **argv)
  1494. {
  1495.   int i;
  1496.   struct ftp *ftp;
  1497.  
  1498.   if ((ftp = current_ftp->cb.ftp) == NULLFTP)
  1499.   {
  1500.     cwprintf(ftp->window, notsess);
  1501.     return 1;
  1502.   }
  1503.  
  1504.   ftp_mpcleanup(ftp);
  1505.  
  1506.   /* must have at least one file */
  1507.   if (argc<2)
  1508.   {
  1509.     cwprintf(ftp->window, "No files requested.\r\n");
  1510.     return 1;
  1511.   }
  1512.  
  1513.   /* alloc for temp name and file list */
  1514.   if ((ftp->mtemp = strdup(tmpnam(NULL)), ftp->mtemp==NULL) ||
  1515.       (ftp->margv = (char **)malloc(argc*sizeof(char *)), ftp->margv==NULL))
  1516.   {
  1517.     ftp_mpcleanup(ftp);
  1518.     cwprintf(ftp->window, nomemforop);
  1519.     return 1;
  1520.   }
  1521.  
  1522.   for (i=0; i<argc; i++)
  1523.     ftp->margv[i] = NULL;
  1524.  
  1525.   ftp->margp = 0;
  1526.  
  1527.   /* Copy file list */
  1528.   for (i=1; i<argc; i++)
  1529.   {
  1530.     if (ftp->margv[i-1] = strdup(argv[i]), ftp->margv[i-1]==NULL)
  1531.     {
  1532.       ftp_mpcleanup(ftp);
  1533.       cwprintf(ftp->window, nomemforop);
  1534.       return 1;
  1535.     }
  1536.   }  
  1537.  
  1538.   /* Initial open of temp list file */
  1539.   if (ftp->fp = fopen(ftp->mtemp, "w"), ftp->fp==NULL)
  1540.   {
  1541.     ftp_mpcleanup(ftp);
  1542.     cwprintf(ftp->window, "Oops - temp file wont open\r\n");
  1543.     return 1;
  1544.   }
  1545.  
  1546.   /* start the ball rolling... */
  1547.   ftp->mpstate = FTPM_LISTING;
  1548.   mprocess(ftp);
  1549.   return 0;
  1550. }
  1551.  
  1552. static int mprocess(struct ftp *ftp)
  1553. {
  1554.   char buf[256];
  1555.  
  1556.   if (ftp->mpstate==FTPM_IDLE)
  1557.     return 0;
  1558.  
  1559.   cwprintf(ftp->window, "mget> ");
  1560.  
  1561.   if (ftp->mpstate==FTPM_LISTING)
  1562.   {
  1563.     if (ftp->margv[ftp->margp]!=NULL)
  1564.     {
  1565.       if (ftp->fp==NULL)
  1566.         ftp->fp = fopen(ftp->mtemp, "a");
  1567.  
  1568.       if (ftp->fp==NULL)
  1569.       {
  1570.         ftp_mpcleanup(ftp);
  1571.         cwprintf(ftp->window, "Temp file wont open - mget aborted\r\n");
  1572.         return 0;
  1573.       }
  1574.  
  1575.       ftp->state = RECEIVING_STATE;
  1576.       ftp->expected_size = 0;
  1577.       ftp->start_time = alarm_timenow () ;
  1578.       if ( ftp->type == IMAGE_TYPE )
  1579.       {
  1580.         ftp->type = IMAGE_PENDING ;
  1581.         sndftpmsg(ftp,"TYPE A\r\n");
  1582.       }
  1583.       ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
  1584.       /* Generate the command to start the transfer */
  1585.       sndftpmsg(ftp,"NLST %s\r\n",ftp->margv[ftp->margp++]);
  1586.       return 1;
  1587.     }
  1588.     else
  1589.     {
  1590.       ftp->mpstate = FTPM_GETFILES;
  1591.       if (ftp->mfp = fopen(ftp->mtemp, "r"), ftp->mtemp==NULL)
  1592.       {
  1593.         ftp_mpcleanup(ftp);
  1594.         cwprintf(ftp->window, "Temp file wont open - mget aborted\r\n");
  1595.         return 0;
  1596.       }
  1597.     }
  1598.   }
  1599.  
  1600.   if (ftp->mpstate == FTPM_GETFILES)
  1601.   {
  1602.     strcpy(buf, "get ");
  1603.  
  1604.     if (fgets(buf+4, 256, ftp->mfp)!=NULL)
  1605.     {
  1606.       cwprintf(ftp->window, "%s\r\n", buf);
  1607.       if (!cmdparse(ftpcmds, buf, ftp->window))
  1608.         return 1;
  1609.       else
  1610.       {
  1611.         ftp_mpcleanup(ftp);
  1612.         cwprintf(ftp->window, "Error, Batch file closed.\r\n");
  1613.       }
  1614.     }
  1615.     else
  1616.     {
  1617.       ftp_mpcleanup(ftp);
  1618.       cwprintf(ftp->window, "MGet completed.\r\n");
  1619.     }  
  1620.     return 0;
  1621.   }
  1622.  
  1623.   return 0;
  1624. }
  1625.