ReactOS 0.4.15-dev-5666-gc548b97
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
17static sigjmp_buf gBrokenCtrlJmp;
18#else
19static jmp_buf gBrokenCtrlJmp;
20#endif /* HAVE_SIGSETJMP */
21
22static void
23BrokenCtrl(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 */
54void
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
73void
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
88static 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
113void
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 */
141void
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 */
167int
168GetTelnetString(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);
185checkChar:
186 if (c == EOF) {
187eof:
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 {
264addChar:
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
273done:
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 */
286int
288{
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);
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);
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);
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
495static int
496SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
497{
499 int result;
500
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
530static int
531SendCommand(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*/
602int
603FTPCmd(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*/
655int
656FTPCmdNoResponse(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
683int
684WaitResponse(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*/
717int
718RCmd(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*/
762int
763FTPStartDataCmd(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
861done:
862 (void) FTPEndDataCmd(cip, 0);
863 return (result);
864} /* FTPStartDataCmd */
865
866
867
868
869void
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);
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);
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);
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
932int
933FTPEndDataCmd(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
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
977int
978BufferGets(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
1027done:
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 */
#define STRNCAT(d, s)
Definition: Strn.h:48
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define isdigit(c)
Definition: acclib.h:68
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define fileno
Definition: acwin.h:102
#define read
Definition: acwin.h:96
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
BOOL Error
Definition: chkdsk.c:66
#define UNUSED(x)
Definition: btrfs_drv.h:82
#define setjmp
Definition: setjmp.h:209
_JBTYPE jmp_buf[_JBLEN]
Definition: setjmp.h:186
#define SIGPIPE
Definition: signal.h:35
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
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
#define WONT
Definition: ftp_var.h:16
#define WILL
Definition: ftp_var.h:17
#define DO
Definition: ftp_var.h:15
#define DONT
Definition: ftp_var.h:14
#define IAC
Definition: ftp_var.h:13
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble n
Definition: glext.h:7729
GLenum src
Definition: glext.h:6340
const GLubyte * c
Definition: glext.h:8905
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
GLenum GLuint GLsizei bufsize
Definition: glext.h:7473
GLenum GLsizei len
Definition: glext.h:6722
GLuint64EXT * result
Definition: glext.h:11304
#define ss
Definition: i386-dis.c:442
_Check_return_opt_ _CRTIMP int __cdecl fgetc(_Inout_ FILE *_File)
#define EOF
Definition: stdio.h:24
_Check_return_opt_ _CRTIMP int __cdecl fputs(_In_z_ const char *_Str, _Inout_ FILE *_File)
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
_Check_return_opt_ _CRTIMP int __cdecl fflush(_Inout_opt_ FILE *_File)
int __cdecl vsprintf(char *_Dest, const char *_Format, va_list _Args)
Definition: sprintf.c:733
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define cout
Definition: iostream.cpp:38
#define cin
Definition: iostream.cpp:37
#define c
Definition: ke_i.h:80
#define SELECT_TYPE_ARG234
Definition: wincfg.h:4
void InitLineList(LineListPtr list)
Definition: linelist.c:54
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
LinePtr AddLine(LineListPtr list, const char *buf1)
Definition: linelist.c:94
POINT cp
Definition: magnifier.c:59
int FTPSetTransferType(const FTPCIPtr cip, int type)
Definition: cmds.c:836
void SendTelnetInterrupt(const FTPCIPtr cip)
Definition: ftp.c:1328
void CloseDataConnection(const FTPCIPtr cip)
Definition: ftp.c:831
int OpenDataConnection(const FTPCIPtr cip, int mode)
Definition: ftp.c:1053
int SetStartOffset(const FTPCIPtr cip, longest_int restartPt)
Definition: ftp.c:853
int SetLinger(const FTPCIPtr cip, int sockfd, int onoff)
Definition: ftp.c:262
int AcceptDataConnection(const FTPCIPtr cip)
Definition: ftp.c:1249
void PrintF(const FTPCIPtr cip, const char *const fmt,...)
Definition: util.c:340
char str16[16]
Definition: util.h:11
char longstring[512]
Definition: util.h:12
#define kDoPerror
Definition: util.h:44
#define kDontPerror
Definition: util.h:45
#define kClosedFileDescriptor
Definition: util.h:47
#define SZ(a)
Definition: util.h:49
int SWrite(int, const char *const, size_t, int, int)
Definition: SWrite.c:90
int SReadline(SReadlineInfo *, char *const, size_t)
Definition: SReadline.c:76
int SWaitUntilReadyForReading(const int sfd, const int tlen)
Definition: SWait.c:7
#define kTimeoutErr
Definition: sio.h:58
ULONG nr
Definition: thread.c:7
int sigsetjmp(sigjmp_buf buf, int savesigs)
void siglongjmp(sigjmp_buf buf, int val)
jmp_buf sigjmp_buf
Definition: port.h:324
int GetTelnetString(const FTPCIPtr, char *, size_t, FILE *, FILE *)
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
#define kFirewallNotInUse
Definition: ncftp.h:388
void(* FTPSigProc)(int)
Definition: ncftp.h:76
#define kSizeUnknown
Definition: ncftp.h:376
#define longest_int
Definition: ncftp.h:68
#define kResponseNoProc
Definition: ncftp.h:310
#define kLibraryMagic
Definition: ncftp.h:65
#define kResponseNoSave
Definition: ncftp.h:309
struct Response * ResponsePtr
#define LIBNCFTP_USE_VAR(a)
Definition: ncftp.h:521
#define kErrCouldNotStartDataTransfer
Definition: ncftp_errno.h:77
#define kNoErr
Definition: ncftp_errno.h:9
#define kErrMallocFailed
Definition: ncftp_errno.h:40
#define kErrSocketWriteFailed
Definition: ncftp_errno.h:52
#define kErrNotConnected
Definition: ncftp_errno.h:76
#define kErrBadMagic
Definition: ncftp_errno.h:55
#define kErrDataTransferFailed
Definition: ncftp_errno.h:78
#define kErrBadParameter
Definition: ncftp_errno.h:56
#define kErrControlTimedOut
Definition: ncftp_errno.h:110
#define kErrInvalidReplyFromServer
Definition: ncftp_errno.h:74
#define kErrRemoteHostClosedConnection
Definition: ncftp_errno.h:75
#define long
Definition: qsort.c:33
int FTPCmd(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:603
int FTPEndDataCmd(const FTPCIPtr cip, int didXfer)
Definition: rcmd.c:933
void DoneWithResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:114
static void SaveLastResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:89
void PrintResponse(const FTPCIPtr cip, LineListPtr llp)
Definition: rcmd.c:74
int BufferGets(char *buf, size_t bufsize, int inStream, char *secondaryBuf, char **secBufPtr, char **secBufLimit, size_t secBufSize)
Definition: rcmd.c:978
void FTPAbortDataTransfer(const FTPCIPtr cip)
Definition: rcmd.c:870
static int SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
Definition: rcmd.c:496
int FTPCmdNoResponse(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:656
int WaitResponse(const FTPCIPtr cip, unsigned int sec)
Definition: rcmd.c:684
int GetResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:287
void TraceResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:55
void ReInitResponse(const FTPCIPtr cip, ResponsePtr rp)
Definition: rcmd.c:142
int RCmd(const FTPCIPtr cip, ResponsePtr rp, const char *cmdspec,...)
Definition: rcmd.c:718
int FTPStartDataCmd(const FTPCIPtr cip, int netMode, int type, longest_int startPoint, const char *cmdspec,...)
Definition: rcmd.c:763
ResponsePtr InitResponse(void)
Definition: rcmd.c:38
#define err(...)
#define calloc
Definition: rosglue.h:14
const WCHAR * str
_Check_return_ _CRTIMP int __cdecl __cdecl eof(_In_ int _FileHandle)
int signal
Definition: except.c:82
static int fd
Definition: io.c:51
#define memset(x, y, z)
Definition: compat.h:39
int firewallType
Definition: ncftp.h:221
FILE * cout
Definition: ncftp.h:189
FTPPrintResponseProc printResponseProc
Definition: ncftp.h:226
int dataTimedOut
Definition: ncftp.h:212
int lastFTPCmdResultNum
Definition: ncftp.h:216
char magic[16]
Definition: ncftp.h:135
LineList lastFTPCmdResultLL
Definition: ncftp.h:215
int dataPortMode
Definition: ncftp.h:152
unsigned int abortTimeout
Definition: ncftp.h:144
longest_int startPoint
Definition: ncftp.h:159
SReadlineInfo ctrlSrl
Definition: ncftp.h:240
unsigned int ctrlTimeout
Definition: ncftp.h:143
FILE * cin
Definition: ncftp.h:188
char lastFTPCmdResultStr[128]
Definition: ncftp.h:214
char user[64]
Definition: ncftp.h:137
Definition: ncftp.h:84
LinePtr first
Definition: ncftp.h:85
Definition: ncftp.h:79
char * line
Definition: ncftp.h:81
LinePtr next
Definition: ncftp.h:80
Definition: ncftp.h:89
int eofOkay
Definition: ncftp.h:94
int hadEof
Definition: ncftp.h:95
int printMode
Definition: ncftp.h:93
int code
Definition: ncftp.h:92
int codeType
Definition: ncftp.h:91
LineList msg
Definition: ncftp.h:90
Definition: inflate.c:139
Definition: winsock.h:66
unsigned long tv_sec
Definition: linux.h:1738
unsigned long tv_usec
Definition: linux.h:1739
#define vsnprintf
Definition: tif_win32.c:406
void int int ULONGLONG int va_list * ap
Definition: winesup.h:36
#define FD_ZERO(set)
Definition: winsock.h:96
#define FD_SET(fd, set)
Definition: winsock.h:89