ReactOS  0.4.13-dev-455-g28ed234
rcmd.c
Go to the documentation of this file.
1 /* rcmd.c
2  *
3  * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4  * All rights reserved.
5  *
6  */
7 
8 #include "syshdrs.h"
9 
10 #if !defined(NO_SIGNALS) && (USE_SIO || !defined(SIGALRM) || !defined(SIGPIPE) || !defined(SIGINT))
11 # define NO_SIGNALS 1
12 #endif
13 
14 #ifndef NO_SIGNALS
15 
16 #ifdef HAVE_SIGSETJMP
17 static sigjmp_buf gBrokenCtrlJmp;
18 #else
19 static jmp_buf gBrokenCtrlJmp;
20 #endif /* HAVE_SIGSETJMP */
21 
22 static void
23 BrokenCtrl(int UNUSED(signumIgnored))
24 {
25  LIBNCFTP_USE_VAR(signumIgnored); /* Shut up gcc */
26 #ifdef HAVE_SIGSETJMP
27  siglongjmp(gBrokenCtrlJmp, 1);
28 #else
29  longjmp(gBrokenCtrlJmp, 1);
30 #endif /* HAVE_SIGSETJMP */
31 } /* BrokenCtrl */
32 
33 #endif /* NO_SIGNALS */
34 
35 
36 /* A 'Response' parameter block is simply zeroed to be considered init'ed. */
39 {
40  ResponsePtr rp;
41 
42  rp = (ResponsePtr) calloc(SZ(1), sizeof(Response));
43  if (rp != NULL)
44  InitLineList(&rp->msg);
45  return (rp);
46 } /* InitResponse */
47 
48 
49 
50 
51 /* If we don't print it to the screen, we may want to save it to our
52  * trace log.
53  */
54 void
56 {
57  LinePtr lp;
58 
59  if (rp != NULL) {
60  lp = rp->msg.first;
61  if (lp != NULL) {
62  PrintF(cip, "%3d: %s\n", rp->code, lp->line);
63  for (lp = lp->next; lp != NULL; lp = lp->next)
64  PrintF(cip, " %s\n", lp->line);
65  }
66  }
67 } /* TraceResponse */
68 
69 
70 
71 
72 
73 void
75 {
76  LinePtr lp;
77 
78  if (llp != NULL) {
79  for (lp = llp->first; lp != NULL; lp = lp->next)
80  PrintF(cip, "%s\n", lp->line);
81  }
82 } /* PrintResponse */
83 
84 
85 
86 
87 
88 static void
90 {
91  if (rp == NULL) {
92  cip->lastFTPCmdResultStr[0] = '\0';
93  cip->lastFTPCmdResultNum = -1;
95  } else if ((rp->msg.first == NULL) || (rp->msg.first->line == NULL)) {
96  cip->lastFTPCmdResultStr[0] = '\0';
97  cip->lastFTPCmdResultNum = rp->code;
99  } else {
101  cip->lastFTPCmdResultNum = rp->code;
102 
103  /* Dispose previous command's line list. */
105 
106  /* Save this command's line list. */
107  cip->lastFTPCmdResultLL = rp->msg;
108  }
109 } /* SaveLastResponse */
110 
111 
112 
113 void
115 {
116  /* Dispose space taken up by the Response, and clear it out
117  * again. For some reason, I like to return memory to zeroed
118  * when not in use.
119  */
120  if (rp != NULL) {
121  TraceResponse(cip, rp);
122  if (cip->printResponseProc != 0) {
123  if ((rp->printMode & kResponseNoProc) == 0)
124  (*cip->printResponseProc)(cip, rp);
125  }
126  if ((rp->printMode & kResponseNoSave) == 0)
127  SaveLastResponse(cip, rp);
128  else
130  (void) memset(rp, 0, sizeof(Response));
131  free(rp);
132  }
133 } /* DoneWithResponse */
134 
135 
136 
137 
138 /* This takes an existing Response and recycles it, by clearing out
139  * the current contents.
140  */
141 void
143 {
144  if (rp != NULL) {
145  TraceResponse(cip, rp);
146  if (cip->printResponseProc != 0) {
147  if ((rp->printMode & kResponseNoProc) == 0)
148  (*cip->printResponseProc)(cip, rp);
149  }
150  if ((rp->printMode & kResponseNoSave) == 0)
151  SaveLastResponse(cip, rp);
152  else
154  (void) memset(rp, 0, sizeof(Response));
155  }
156 } /* ReInitResponse */
157 
158 
159 
160 
161 #ifndef NO_SIGNALS
162 
163 /* Since the control stream is defined by the Telnet protocol (RFC 854),
164  * we follow Telnet rules when reading the control stream. We use this
165  * routine when we want to read a response from the host.
166  */
167 int
168 GetTelnetString(const FTPCIPtr cip, char *str, size_t siz, FILE *cin, FILE *cout)
169 {
170  int c;
171  size_t n;
172  int eofError;
173  char *cp;
174 
175  cp = str;
176  --siz; /* We'll need room for the \0. */
177 
178  if ((cin == NULL) || (cout == NULL)) {
179  eofError = -1;
180  goto done;
181  }
182 
183  for (n = (size_t)0, eofError = 0; ; ) {
184  c = fgetc(cin);
185 checkChar:
186  if (c == EOF) {
187 eof:
188  eofError = -1;
189  break;
190  } else if (c == '\r') {
191  /* A telnet string can have a CR by itself. But to denote that,
192  * the protocol uses \r\0; an end of line is denoted \r\n.
193  */
194  c = fgetc(cin);
195  if (c == '\n') {
196  /* Had \r\n, so done. */
197  goto done;
198  } else if (c == EOF) {
199  goto eof;
200  } else if (c == '\0') {
201  c = '\r';
202  goto addChar;
203  } else {
204  /* Telnet protocol violation! */
205  goto checkChar;
206  }
207  } else if (c == '\n') {
208  /* Really shouldn't get here. If we do, the other side
209  * violated the TELNET protocol, since eoln's are CR/LF,
210  * and not just LF.
211  */
212  PrintF(cip, "TELNET protocol violation: raw LF.\n");
213  goto done;
214  } else if (c == IAC) {
215  /* Since the control connection uses the TELNET protocol,
216  * we have to handle some of its commands ourselves.
217  * IAC is the protocol's escape character, meaning that
218  * the next character after the IAC (Interpret as Command)
219  * character is a telnet command. But, if there just
220  * happened to be a character in the text stream with the
221  * same numerical value of IAC, 255, the sender denotes
222  * that by having an IAC followed by another IAC.
223  */
224 
225  /* Get the telnet command. */
226  c = fgetc(cin);
227 
228  switch (c) {
229  case WILL:
230  case WONT:
231  /* Get the option code. */
232  c = fgetc(cin);
233 
234  /* Tell the other side that we don't want
235  * to do what they're offering to do.
236  */
237  (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
238  (void) fflush(cout);
239  break;
240  case DO:
241  case DONT:
242  /* Get the option code. */
243  c = fgetc(cin);
244 
245  /* The other side said they are DOing (or not)
246  * something, which would happen if our side
247  * asked them to. Since we didn't do that,
248  * ask them to not do this option.
249  */
250  (void) fprintf(cout, "%c%c%c",IAC,WONT,c);
251  (void) fflush(cout);
252  break;
253 
254  case EOF:
255  goto eof;
256 
257  default:
258  /* Just add this character, since it was most likely
259  * just an escaped IAC character.
260  */
261  goto addChar;
262  }
263  } else {
264 addChar:
265  /* If the buffer supplied has room, add this character to it. */
266  if (n < siz) {
267  *cp++ = c;
268  ++n;
269  }
270  }
271  }
272 
273 done:
274  *cp = '\0';
275  return (eofError);
276 } /* GetTelnetString */
277 
278 #endif /* NO_SIGNALS */
279 
280 
281 
282 /* Returns 0 if a response was read, or (-1) if an error occurs.
283  * This reads the entire response text into a LineList, which is kept
284  * in the 'Response' structure.
285  */
286 int
288 {
289  longstring str;
290  int eofError;
291  str16 code;
292  char *cp;
293  int continuation;
294  volatile FTPCIPtr vcip;
295 #ifdef NO_SIGNALS
296  int result;
297 #else /* NO_SIGNALS */
298  volatile FTPSigProc osigpipe;
299  int sj;
300 #endif /* NO_SIGNALS */
301 
302  /* RFC 959 states that a reply may span multiple lines. A single
303  * line message would have the 3-digit code <space> then the msg.
304  * A multi-line message would have the code <dash> and the first
305  * line of the msg, then additional lines, until the last line,
306  * which has the code <space> and last line of the msg.
307  *
308  * For example:
309  * 123-First line
310  * Second line
311  * 234 A line beginning with numbers
312  * 123 The last line
313  */
314 
315 #ifdef NO_SIGNALS
316  vcip = cip;
317 #else /* NO_SIGNALS */
318  osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenCtrl);
319  vcip = cip;
320 
321 #ifdef HAVE_SIGSETJMP
322  sj = sigsetjmp(gBrokenCtrlJmp, 1);
323 #else
324  sj = setjmp(gBrokenCtrlJmp);
325 #endif /* HAVE_SIGSETJMP */
326 
327  if (sj != 0) {
328  (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
329  FTPShutdownHost(vcip);
331  return(vcip->errNo);
332  }
333 #endif /* NO_SIGNALS */
334 
335 #ifdef NO_SIGNALS
336  cp = str;
337  eofError = 0;
338  if (cip->dataTimedOut > 0) {
339  /* Give up immediately unless the server had already
340  * sent a message. Odds are since the data is timed
341  * out, so is the control.
342  */
343  if (SWaitUntilReadyForReading(cip->ctrlSocketR, 0) == 0) {
344  /* timeout */
345  Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n");
346  FTPShutdownHost(vcip);
347  cip->errNo = kErrControlTimedOut;
348  return (cip->errNo);
349  }
350  }
351  result = SReadline(&cip->ctrlSrl, str, sizeof(str) - 1);
352  if (result == kTimeoutErr) {
353  /* timeout */
354  Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n");
355  FTPShutdownHost(vcip);
356  cip->errNo = kErrControlTimedOut;
357  return (cip->errNo);
358  } else if (result == 0) {
359  /* eof */
360  eofError = 1;
361  rp->hadEof = 1;
362  if (rp->eofOkay == 0)
363  Error(cip, kDontPerror, "Remote host has closed the connection.\n");
364  FTPShutdownHost(vcip);
366  return (cip->errNo);
367  } else if (result < 0) {
368  /* error */
369  Error(cip, kDoPerror, "Could not read reply from control connection");
370  FTPShutdownHost(vcip);
372  return (cip->errNo);
373  }
374 
375  if (str[result - 1] == '\n')
376  str[result - 1] = '\0';
377 
378 #else /* NO_SIGNALS */
379  /* Get the first line of the response. */
380  eofError = GetTelnetString(cip, str, sizeof(str), cip->cin, cip->cout);
381 
382  cp = str;
383  if (*cp == '\0') {
384  if (eofError < 0) {
385  /* No bytes read for reply, and EOF detected. */
386  rp->hadEof = 1;
387  if (rp->eofOkay == 0)
388  Error(cip, kDontPerror, "Remote host has closed the connection.\n");
389  FTPShutdownHost(vcip);
391  (void) signal(SIGPIPE, osigpipe);
392  return(cip->errNo);
393  }
394  }
395 #endif /* NO_SIGNALS */
396 
397  if (!isdigit((int) *cp)) {
398  Error(cip, kDontPerror, "Invalid reply: \"%s\"\n", cp);
400 #ifndef NO_SIGNALS
401  (void) signal(SIGPIPE, osigpipe);
402 #endif
403  return (cip->errNo);
404  }
405 
406  rp->codeType = *cp - '0';
407  cp += 3;
408  continuation = (*cp == '-');
409  *cp++ = '\0';
410  (void) STRNCPY(code, str);
411  rp->code = atoi(code);
412  (void) AddLine(&rp->msg, cp);
413  if (eofError < 0) {
414  /* Read reply, but EOF was there also. */
415  rp->hadEof = 1;
416  }
417 
418  while (continuation) {
419 
420 #ifdef NO_SIGNALS
421  result = SReadline(&cip->ctrlSrl, str, sizeof(str) - 1);
422  if (result == kTimeoutErr) {
423  /* timeout */
424  Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n");
425  FTPShutdownHost(vcip);
426  cip->errNo = kErrControlTimedOut;
427  return (cip->errNo);
428  } else if (result == 0) {
429  /* eof */
430  eofError = 1;
431  rp->hadEof = 1;
432  if (rp->eofOkay == 0)
433  Error(cip, kDontPerror, "Remote host has closed the connection.\n");
434  FTPShutdownHost(vcip);
436  return (cip->errNo);
437  } else if (result < 0) {
438  /* error */
439  Error(cip, kDoPerror, "Could not read reply from control connection");
440  FTPShutdownHost(vcip);
442  return (cip->errNo);
443  }
444 
445  if (str[result - 1] == '\n')
446  str[result - 1] = '\0';
447 #else /* NO_SIGNALS */
448  eofError = GetTelnetString(cip, str, sizeof(str), cip->cin, cip->cout);
449  if (eofError < 0) {
450  /* Read reply, but EOF was there also. */
451  rp->hadEof = 1;
452  continuation = 0;
453  }
454 #endif /* NO_SIGNALS */
455  cp = str;
456  if (strncmp(code, cp, SZ(3)) == 0) {
457  cp += 3;
458  if (*cp == ' ')
459  continuation = 0;
460  ++cp;
461  }
462  (void) AddLine(&rp->msg, cp);
463  }
464 
465  if (rp->code == 421) {
466  /*
467  * 421 Service not available, closing control connection.
468  * This may be a reply to any command if the service knows it
469  * must shut down.
470  */
471  if (rp->eofOkay == 0)
472  Error(cip, kDontPerror, "Remote host has closed the connection.\n");
473  FTPShutdownHost(vcip);
475 #ifndef NO_SIGNALS
476  (void) signal(SIGPIPE, osigpipe);
477 #endif
478  return(cip->errNo);
479  }
480 
481 #ifndef NO_SIGNALS
482  (void) signal(SIGPIPE, osigpipe);
483 #endif
484  return (kNoErr);
485 } /* GetResponse */
486 
487 
488 
489 
490 /* This creates the complete command text to send, and writes it
491  * on the stream.
492  */
493 #ifdef NO_SIGNALS
494 
495 static int
496 SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
497 {
499  int result;
500 
501  if (cip->ctrlSocketW != kClosedFileDescriptor) {
502 #ifdef HAVE_VSNPRINTF
503  (void) vsnprintf(command, sizeof(command) - 1, cmdspec, ap);
504  command[sizeof(command) - 1] = '\0';
505 #else
506  (void) vsprintf(command, cmdspec, ap);
507 #endif
508  if ((strncmp(command, "PASS", SZ(4)) != 0) || ((strcmp(cip->user, "anonymous") == 0) && (cip->firewallType == kFirewallNotInUse)))
509  PrintF(cip, "Cmd: %s\n", command);
510  else
511  PrintF(cip, "Cmd: %s\n", "PASS xxxxxxxx");
512  (void) STRNCAT(command, "\r\n"); /* Use TELNET end-of-line. */
513  cip->lastFTPCmdResultStr[0] = '\0';
514  cip->lastFTPCmdResultNum = -1;
515 
516  result = SWrite(cip->ctrlSocketW, command, strlen(command), (int) cip->ctrlTimeout, 0);
517 
518  if (result < 0) {
520  Error(cip, kDoPerror, "Could not write to control stream.\n");
521  return (cip->errNo);
522  }
523  return (kNoErr);
524  }
525  return (kErrNotConnected);
526 } /* SendCommand */
527 
528 #else /* NO_SIGNALS */
529 
530 static int
531 SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
532 {
534  int result;
535  volatile FTPCIPtr vcip;
536  volatile FTPSigProc osigpipe;
537  int sj;
538 
539  if (cip->cout != NULL) {
540 #ifdef HAVE_VSNPRINTF
541  (void) vsnprintf(command, sizeof(command) - 1, cmdspec, ap);
542  command[sizeof(command) - 1] = '\0';
543 #else
544  (void) vsprintf(command, cmdspec, ap);
545 #endif
546  if ((strncmp(command, "PASS", SZ(4)) != 0) || ((strcmp(cip->user, "anonymous") == 0) && (cip->firewallType == kFirewallNotInUse)))
547  PrintF(cip, "Cmd: %s\n", command);
548  else
549  PrintF(cip, "Cmd: %s\n", "PASS xxxxxxxx");
550  (void) STRNCAT(command, "\r\n"); /* Use TELNET end-of-line. */
551  cip->lastFTPCmdResultStr[0] = '\0';
552  cip->lastFTPCmdResultNum = -1;
553 
554  osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenCtrl);
555  vcip = cip;
556 
557 #ifdef HAVE_SIGSETJMP
558  sj = sigsetjmp(gBrokenCtrlJmp, 1);
559 #else
560  sj = setjmp(gBrokenCtrlJmp);
561 #endif /* HAVE_SIGSETJMP */
562 
563  if (sj != 0) {
564  (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
565  FTPShutdownHost(vcip);
566  if (vcip->eofOkay == 0) {
567  Error(cip, kDontPerror, "Remote host has closed the connection.\n");
569  return(vcip->errNo);
570  }
571  return (kNoErr);
572  }
573 
574  result = fputs(command, cip->cout);
575  if (result < 0) {
576  (void) signal(SIGPIPE, osigpipe);
578  Error(cip, kDoPerror, "Could not write to control stream.\n");
579  return (cip->errNo);
580  }
581  result = fflush(cip->cout);
582  if (result < 0) {
583  (void) signal(SIGPIPE, osigpipe);
585  Error(cip, kDoPerror, "Could not write to control stream.\n");
586  return (cip->errNo);
587  }
588  (void) signal(SIGPIPE, osigpipe);
589  return (kNoErr);
590  }
591  return (kErrNotConnected);
592 } /* SendCommand */
593 #endif /* NO_SIGNALS */
594 
595 
596 
597 /* For "simple" (i.e. not data transfer) commands, this routine is used
598  * to send the command and receive one response. It returns the codeType
599  * field of the 'Response' as the result, or a negative number upon error.
600  */
601 /*VARARGS*/
602 int
603 FTPCmd(const FTPCIPtr cip, const char *const cmdspec, ...)
604 {
605  va_list ap;
606  int result;
607  ResponsePtr rp;
608 
609  if (cip == NULL)
610  return (kErrBadParameter);
611  if (strcmp(cip->magic, kLibraryMagic))
612  return (kErrBadMagic);
613 
614  rp = InitResponse();
615  if (rp == NULL) {
617  cip->errNo = kErrMallocFailed;
618  Error(cip, kDontPerror, "Malloc failed.\n");
619  return (cip->errNo);
620  }
621 
622  va_start(ap, cmdspec);
623 #ifndef NO_SIGNALS
624  if (cip->ctrlTimeout > 0)
625  (void) alarm(cip->ctrlTimeout);
626 #endif /* NO_SIGNALS */
627  result = SendCommand(cip, cmdspec, ap);
628  va_end(ap);
629  if (result < 0) {
630 #ifndef NO_SIGNALS
631  if (cip->ctrlTimeout > 0)
632  (void) alarm(0);
633 #endif /* NO_SIGNALS */
634  return (result);
635  }
636 
637  /* Get the response to the command we sent. */
638  result = GetResponse(cip, rp);
639 #ifndef NO_SIGNALS
640  if (cip->ctrlTimeout > 0)
641  (void) alarm(0);
642 #endif /* NO_SIGNALS */
643 
644  if (result == kNoErr)
645  result = rp->codeType;
646  DoneWithResponse(cip, rp);
647  return (result);
648 } /* FTPCmd */
649 
650 
651 
652 
653 /* This is for debugging the library -- don't use. */
654 /*VARARGS*/
655 int
656 FTPCmdNoResponse(const FTPCIPtr cip, const char *const cmdspec, ...)
657 {
658  va_list ap;
659 
660  if (cip == NULL)
661  return (kErrBadParameter);
662  if (strcmp(cip->magic, kLibraryMagic))
663  return (kErrBadMagic);
664 
665  va_start(ap, cmdspec);
666 #ifndef NO_SIGNALS
667  if (cip->ctrlTimeout > 0)
668  (void) alarm(cip->ctrlTimeout);
669 #endif /* NO_SIGNALS */
670  (void) SendCommand(cip, cmdspec, ap);
671 #ifndef NO_SIGNALS
672  if (cip->ctrlTimeout > 0)
673  (void) alarm(0);
674 #endif /* NO_SIGNALS */
675  va_end(ap);
676 
677  return (kNoErr);
678 } /* FTPCmdNoResponse */
679 
680 
681 
682 
683 int
684 WaitResponse(const FTPCIPtr cip, unsigned int sec)
685 {
686  int result;
687  fd_set ss;
688  struct timeval tv;
689  int fd;
690 
691 #ifdef NO_SIGNALS
692  fd = cip->ctrlSocketR;
693 #else /* NO_SIGNALS */
694  if (cip->cin == NULL)
695  return (-1);
696  fd = fileno(cip->cin);
697 #endif /* NO_SIGNALS */
698  if (fd < 0)
699  return (-1);
700  FD_ZERO(&ss);
701  FD_SET(fd, &ss);
702  tv.tv_sec = (unsigned long) sec;
703  tv.tv_usec = 0;
704  result = select(fd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, &tv);
705  return (result);
706 } /* WaitResponse */
707 
708 
709 
710 
711 /* For "simple" (i.e. not data transfer) commands, this routine is used
712  * to send the command and receive one response. It returns the codeType
713  * field of the 'Response' as the result, or a negative number upon error.
714  */
715 
716 /*VARARGS*/
717 int
718 RCmd(const FTPCIPtr cip, ResponsePtr rp, const char *cmdspec, ...)
719 {
720  va_list ap;
721  int result;
722 
723  if (cip == NULL)
724  return (kErrBadParameter);
725  if (strcmp(cip->magic, kLibraryMagic))
726  return (kErrBadMagic);
727 
728  va_start(ap, cmdspec);
729 #ifndef NO_SIGNALS
730  if (cip->ctrlTimeout > 0)
731  (void) alarm(cip->ctrlTimeout);
732 #endif /* NO_SIGNALS */
733  result = SendCommand(cip, cmdspec, ap);
734  va_end(ap);
735  if (result < 0) {
736 #ifndef NO_SIGNALS
737  if (cip->ctrlTimeout > 0)
738  (void) alarm(0);
739 #endif /* NO_SIGNALS */
740  return (result);
741  }
742 
743  /* Get the response to the command we sent. */
744  result = GetResponse(cip, rp);
745 #ifndef NO_SIGNALS
746  if (cip->ctrlTimeout > 0)
747  (void) alarm(0);
748 #endif /* NO_SIGNALS */
749 
750  if (result == kNoErr)
751  result = rp->codeType;
752  return (result);
753 } /* RCmd */
754 
755 
756 
757 /* Returns -1 if an error occurred, or 0 if not.
758  * This differs from RCmd, which returns the code class of a response.
759  */
760 
761 /*VARARGS*/
762 int
763 FTPStartDataCmd(const FTPCIPtr cip, int netMode, int type, longest_int startPoint, const char *cmdspec, ...)
764 {
765  va_list ap;
766  int result;
767  int respCode;
768  ResponsePtr rp;
769 
770  if (cip == NULL)
771  return (kErrBadParameter);
772  if (strcmp(cip->magic, kLibraryMagic))
773  return (kErrBadMagic);
774 
776  if (result < 0)
777  return (result);
778 
779  /* Re-set the cancellation flag. */
780  cip->cancelXfer = 0;
781 
782  /* To transfer data, we do these things in order as specifed by
783  * the RFC.
784  *
785  * First, we tell the other side to set up a data line. This
786  * is done below by calling OpenDataConnection(), which sets up
787  * the socket. When we do that, the other side detects a connection
788  * attempt, so it knows we're there. Then tell the other side
789  * (by using listen()) that we're willing to receive a connection
790  * going to our side.
791  */
792 
793  if ((result = OpenDataConnection(cip, cip->dataPortMode)) < 0)
794  goto done;
795 
796  /* If asked, attempt to start at a later position in the remote file. */
797  if (startPoint != (longest_int) 0) {
798  if ((startPoint == kSizeUnknown) || ((result = SetStartOffset(cip, startPoint)) != 0))
799  startPoint = (longest_int) 0;
800  }
801  cip->startPoint = startPoint;
802 
803  /* Now we tell the server what we want to do. This sends the
804  * the type of transfer we want (RETR, STOR, LIST, etc) and the
805  * parameters for that (files to send, directories to list, etc).
806  */
807  va_start(ap, cmdspec);
808 #ifndef NO_SIGNALS
809  if (cip->ctrlTimeout > 0)
810  (void) alarm(cip->ctrlTimeout);
811 #endif /* NO_SIGNALS */
812  result = SendCommand(cip, cmdspec, ap);
813  va_end(ap);
814  if (result < 0) {
815 #ifndef NO_SIGNALS
816  if (cip->ctrlTimeout > 0)
817  (void) alarm(0);
818 #endif /* NO_SIGNALS */
819  goto done;
820  }
821 
822  /* Get the response to the transfer command we sent, to see if
823  * they can accomodate the request. If everything went okay,
824  * we will get a preliminary response saying that the transfer
825  * initiation was successful and that the data is there for
826  * reading (for retrieves; for sends, they will be waiting for
827  * us to send them something).
828  */
829  rp = InitResponse();
830  if (rp == NULL) {
831  Error(cip, kDontPerror, "Malloc failed.\n");
832  cip->errNo = kErrMallocFailed;
833  result = cip->errNo;
834  goto done;
835  }
836  result = GetResponse(cip, rp);
837 #ifndef NO_SIGNALS
838  if (cip->ctrlTimeout > 0)
839  (void) alarm(0);
840 #endif /* NO_SIGNALS */
841 
842  if (result < 0)
843  goto done;
844  respCode = rp->codeType;
845  DoneWithResponse(cip, rp);
846 
847  if (respCode > 2) {
849  result = cip->errNo;
850  goto done;
851  }
852 
853  /* Now we accept the data connection that the other side is offering
854  * to us. Then we can do the actual I/O on the data we want.
855  */
856  cip->netMode = netMode;
857  if ((result = AcceptDataConnection(cip)) < 0)
858  goto done;
859  return (kNoErr);
860 
861 done:
862  (void) FTPEndDataCmd(cip, 0);
863  return (result);
864 } /* FTPStartDataCmd */
865 
866 
867 
868 
869 void
871 {
872  ResponsePtr rp;
873  int result;
874 
875  if (cip->dataSocket != kClosedFileDescriptor) {
876  PrintF(cip, "Starting abort sequence.\n");
877  SendTelnetInterrupt(cip); /* Probably could get by w/o doing this. */
878 
879  result = FTPCmdNoResponse(cip, "ABOR");
880  if (result != kNoErr) {
881  /* Linger could cause close to block, so unset it. */
882  (void) SetLinger(cip, cip->dataSocket, 0);
883  CloseDataConnection(cip);
884  PrintF(cip, "Could not send abort command.\n");
885  return;
886  }
887 
888  if (cip->abortTimeout > 0) {
889  result = WaitResponse(cip, (unsigned int) cip->abortTimeout);
890  if (result <= 0) {
891  /* Error or no response received to ABOR in time. */
892  (void) SetLinger(cip, cip->dataSocket, 0);
893  CloseDataConnection(cip);
894  PrintF(cip, "No response received to abort request.\n");
895  return;
896  }
897  }
898 
899  rp = InitResponse();
900  if (rp == NULL) {
901  Error(cip, kDontPerror, "Malloc failed.\n");
902  cip->errNo = kErrMallocFailed;
903  result = cip->errNo;
904  return;
905  }
906 
907  result = GetResponse(cip, rp);
908  if (result < 0) {
909  /* Shouldn't happen, and doesn't matter if it does. */
910  (void) SetLinger(cip, cip->dataSocket, 0);
911  CloseDataConnection(cip);
912  PrintF(cip, "Invalid response to abort request.\n");
913  DoneWithResponse(cip, rp);
914  return;
915  }
916  DoneWithResponse(cip, rp);
917 
918  /* A response to the abort request has been received.
919  * Now the only thing left to do is close the data
920  * connection, making sure to turn off linger mode
921  * since we don't care about straggling data bits.
922  */
923  (void) SetLinger(cip, cip->dataSocket, 0);
924  CloseDataConnection(cip); /* Must close (by protocol). */
925  PrintF(cip, "End abort.\n");
926  }
927 } /* FTPAbortDataTransfer */
928 
929 
930 
931 
932 int
933 FTPEndDataCmd(const FTPCIPtr cip, int didXfer)
934 {
935  int result;
936  int respCode;
937  ResponsePtr rp;
938 
939  if (cip == NULL)
940  return (kErrBadParameter);
941  if (strcmp(cip->magic, kLibraryMagic))
942  return (kErrBadMagic);
943 
944  CloseDataConnection(cip);
945  result = kNoErr;
946  if (didXfer) {
947  /* Get the response to the data transferred. Most likely a message
948  * saying that the transfer completed succesfully. However, if
949  * we tried to abort the transfer using ABOR, we will have a response
950  * to that command instead.
951  */
952  rp = InitResponse();
953  if (rp == NULL) {
954  Error(cip, kDontPerror, "Malloc failed.\n");
955  cip->errNo = kErrMallocFailed;
956  result = cip->errNo;
957  return (result);
958  }
959  result = GetResponse(cip, rp);
960  if (result < 0)
961  return (result);
962  respCode = rp->codeType;
963  DoneWithResponse(cip, rp);
964  if (respCode != 2) {
966  result = cip->errNo;
967  } else {
968  result = kNoErr;
969  }
970  }
971  return (result);
972 } /* FTPEndDataCmd */
973 
974 
975 
976 
977 int
978 BufferGets(char *buf, size_t bufsize, int inStream, char *secondaryBuf, char **secBufPtr, char **secBufLimit, size_t secBufSize)
979 {
980  int err;
981  char *src;
982  char *dst;
983  char *dstlim;
984  int len;
985  int nr;
986  int haveEof = 0;
987 
988  err = 0;
989  dst = buf;
990  dstlim = dst + bufsize - 1; /* Leave room for NUL. */
991  src = (*secBufPtr);
992  for ( ; dst < dstlim; ) {
993  if (src >= (*secBufLimit)) {
994  /* Fill the buffer. */
995 
996 /* Don't need to poll it here. The routines that use BufferGets don't
997  * need any special processing during timeouts (i.e. progress reports),
998  * so go ahead and just let it block until there is data to read.
999  */
1000  nr = (int) read(inStream, secondaryBuf, secBufSize);
1001  if (nr == 0) {
1002  /* EOF. */
1003  haveEof = 1;
1004  goto done;
1005  } else if (nr < 0) {
1006  /* Error. */
1007  err = -1;
1008  goto done;
1009  }
1010  (*secBufPtr) = secondaryBuf;
1011  (*secBufLimit) = secondaryBuf + nr;
1012  src = (*secBufPtr);
1013  if (nr < (int) secBufSize)
1014  src[nr] = '\0';
1015  }
1016  if (*src == '\r') {
1017  ++src;
1018  } else {
1019  if (*src == '\n') {
1020  /* *dst++ = *src++; */ ++src;
1021  goto done;
1022  }
1023  *dst++ = *src++;
1024  }
1025  }
1026 
1027 done:
1028  (*secBufPtr) = src;
1029  *dst = '\0';
1030  len = (int) (dst - buf);
1031  if (err < 0)
1032  return (err);
1033  if ((len == 0) && (haveEof == 1))
1034  return (-1);
1035  return (len); /* May be zero, if a blank line. */
1036 } /* BufferGets */
1037 
1038 /* eof */
Definition: winsock.h:66
int dataTimedOut
Definition: ncftp.h:212
#define SELECT_TYPE_ARG234
Definition: wincfg.h:4
LineList lastFTPCmdResultLL
Definition: ncftp.h:215
#define vsnprintf
Definition: tif_win32.c:406
#define kResponseNoProc
Definition: ncftp.h:310
int printMode
Definition: ncftp.h:93
FILE * cin
Definition: ncftp.h:188
unsigned int ctrlTimeout
Definition: ncftp.h:143
jmp_buf sigjmp_buf
Definition: port.h:324
#define kErrBadParameter
Definition: ncftp_errno.h:56
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
int RCmd(const FTPCIPtr cip, ResponsePtr rp, const char *cmdspec,...)
Definition: rcmd.c:718
#define kResponseNoSave
Definition: ncftp.h:309
ULONG nr
Definition: thread.c:7
int SetStartOffset(const FTPCIPtr cip, longest_int restartPt)
Definition: ftp.c:853
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define DONT
Definition: ftp_var.h:14
void FTPAbortDataTransfer(const FTPCIPtr cip)
Definition: rcmd.c:870
void CloseDataConnection(const FTPCIPtr cip)
Definition: ftp.c:831
int FTPEndDataCmd(const FTPCIPtr cip, int didXfer)
Definition: rcmd.c:933
int GetResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:287
#define free
Definition: debug_ros.c:5
unsigned long tv_sec
Definition: linux.h:1738
int FTPCmdNoResponse(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:656
#define kErrDataTransferFailed
Definition: ncftp_errno.h:78
char user[64]
Definition: ncftp.h:137
GLdouble n
Definition: glext.h:7729
#define WILL
Definition: ftp_var.h:17
#define kErrInvalidReplyFromServer
Definition: ncftp_errno.h:74
LinePtr next
Definition: ncftp.h:80
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
int FTPSetTransferType(const FTPCIPtr cip, int type)
Definition: cmds.c:836
void SendTelnetInterrupt(const FTPCIPtr cip)
Definition: ftp.c:1328
static int fd
Definition: io.c:51
static void SaveLastResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:89
#define kErrMallocFailed
Definition: ncftp_errno.h:40
void DoneWithResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:114
#define kFirewallNotInUse
Definition: ncftp.h:388
#define FD_ZERO(set)
Definition: winsock.h:96
GLenum GLuint GLsizei bufsize
Definition: glext.h:7473
#define FD_SET(fd, set)
Definition: winsock.h:89
#define LIBNCFTP_USE_VAR(a)
Definition: ncftp.h:521
void PrintResponse(const FTPCIPtr cip, LineListPtr llp)
Definition: rcmd.c:74
char magic[16]
Definition: ncftp.h:135
int FTPCmd(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:603
char str16[16]
Definition: util.h:11
int SWaitUntilReadyForReading(const int sfd, const int tlen)
Definition: SWait.c:7
#define DO
Definition: ftp_var.h:15
int BufferGets(char *buf, size_t bufsize, int inStream, char *secondaryBuf, char **secBufPtr, char **secBufLimit, size_t secBufSize)
Definition: rcmd.c:978
#define kErrControlTimedOut
Definition: ncftp_errno.h:110
#define cout
Definition: iostream.cpp:38
#define va_end(ap)
Definition: acmsvcex.h:90
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define cin
Definition: iostream.cpp:37
const WCHAR * str
smooth NULL
Definition: ftsmooth.c:416
unsigned long tv_usec
Definition: linux.h:1739
#define kTimeoutErr
Definition: sio.h:58
void TraceResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:55
int SWrite(int, const char *const, size_t, int, int)
Definition: SWrite.c:90
int firewallType
Definition: ncftp.h:221
char * va_list
Definition: acmsvcex.h:78
#define UNUSED(x)
Definition: btrfs_drv.h:81
int SReadline(SReadlineInfo *, char *const, size_t)
Definition: SReadline.c:76
int longjmp(jmp_buf buf, int retval)
#define isdigit(c)
Definition: acclib.h:68
int GetTelnetString(const FTPCIPtr, char *, size_t, FILE *, FILE *)
int lastFTPCmdResultNum
Definition: ncftp.h:216
#define STRNCAT(d, s)
Definition: Strn.h:48
int code
Definition: ncftp.h:92
#define kErrNotConnected
Definition: ncftp_errno.h:76
void siglongjmp(sigjmp_buf buf, int val)
int OpenDataConnection(const FTPCIPtr cip, int mode)
Definition: ftp.c:1053
_Check_return_ _CRTIMP int __cdecl fileno(_In_ FILE *_File)
#define longest_int
Definition: ncftp.h:68
#define kErrBadMagic
Definition: ncftp_errno.h:55
int sigsetjmp(sigjmp_buf buf, int savesigs)
const GLubyte * c
Definition: glext.h:8905
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
LinePtr AddLine(LineListPtr list, const char *buf1)
Definition: linelist.c:94
BOOL Error
Definition: chkdsk.c:66
#define kErrSocketWriteFailed
Definition: ncftp_errno.h:52
struct Response * ResponsePtr
void(* FTPSigProc)(int)
Definition: ncftp.h:76
int codeType
Definition: ncftp.h:91
Definition: ncftp.h:89
Definition: ncftp.h:79
#define SIGPIPE
Definition: signal.h:35
int signal
Definition: xcptfil.c:12
Definition: ncftp.h:84
char lastFTPCmdResultStr[128]
Definition: ncftp.h:214
#define kClosedFileDescriptor
Definition: util.h:47
#define kDontPerror
Definition: util.h:45
#define kDoPerror
Definition: util.h:44
GLenum GLsizei len
Definition: glext.h:6722
FILE * cout
Definition: ncftp.h:189
LinePtr first
Definition: ncftp.h:85
GLenum src
Definition: glext.h:6340
#define err(...)
int AcceptDataConnection(const FTPCIPtr cip)
Definition: ftp.c:1249
#define SZ(a)
Definition: util.h:49
int code
Definition: i386-dis.c:3591
int FTPStartDataCmd(const FTPCIPtr cip, int netMode, int type, longest_int startPoint, const char *cmdspec,...)
Definition: rcmd.c:763
_Check_return_ _CRTIMP int __cdecl __cdecl eof(_In_ int _FileHandle)
LineList msg
Definition: ncftp.h:90
void PrintF(const FTPCIPtr cip, const char *const fmt,...)
Definition: util.c:340
FTPPrintResponseProc printResponseProc
Definition: ncftp.h:226
longest_int startPoint
Definition: ncftp.h:159
void ReInitResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:142
_Check_return_opt_ _CRTIMP int __cdecl fflush(_Inout_opt_ FILE *_File)
#define long
Definition: qsort.c:33
int __cdecl vsprintf(char *_Dest, const char *_Format, va_list _Args)
Definition: sprintf.c:733
GLenum GLenum dst
Definition: glext.h:6340
ResponsePtr InitResponse(void)
Definition: rcmd.c:38
void InitLineList(LineListPtr list)
Definition: linelist.c:54
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define setjmp
Definition: setjmp.h:183
#define IAC
Definition: ftp_var.h:13
int SetLinger(const FTPCIPtr cip, int sockfd, int onoff)
Definition: ftp.c:262
char longstring[512]
Definition: util.h:12
int command(const char *fmt,...)
Definition: ftp.c:266
static int SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
Definition: rcmd.c:496
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define EOF
Definition: stdio.h:24
int hadEof
Definition: ncftp.h:95
POINT cp
Definition: magnifier.c:59
#define calloc
Definition: rosglue.h:14
#define kSizeUnknown
Definition: ncftp.h:376
void int int ULONGLONG int va_list * ap
Definition: winesup.h:32
#define kLibraryMagic
Definition: ncftp.h:65
#define kErrCouldNotStartDataTransfer
Definition: ncftp_errno.h:77
#define kErrRemoteHostClosedConnection
Definition: ncftp_errno.h:75
#define c
Definition: ke_i.h:80
#define kNoErr
Definition: ncftp_errno.h:9
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
struct Response Response
unsigned int abortTimeout
Definition: ncftp.h:144
#define WONT
Definition: ftp_var.h:16
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
long jmp_buf[100]
Definition: of.h:11
int WaitResponse(const FTPCIPtr cip, unsigned int sec)
Definition: rcmd.c:684
SReadlineInfo ctrlSrl
Definition: ncftp.h:240
#define ss
Definition: i386-dis.c:432
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
char * line
Definition: ncftp.h:81
_Check_return_opt_ _CRTIMP int __cdecl fputs(_In_z_ const char *_Str, _Inout_ FILE *_File)
int eofOkay
Definition: ncftp.h:94
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
int dataPortMode
Definition: ncftp.h:152
_Check_return_opt_ _CRTIMP int __cdecl fgetc(_Inout_ FILE *_File)
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31