NSTask / NSPipe / FTP
NSTask / NSPipe / FTP
- Subject: NSTask / NSPipe / FTP
- From: John Pannell <email@hidden>
- Date: Fri, 21 Sep 2001 16:02:22 -0600
Hi there-
I'm working on a program that wraps the command line FTP program in a
GUI, using NSTask, NSPipe, etc. I had success doing this with ping,
netstat, and a few other programs, but FTP is giving me fits - It
doesn't seem to send the command line output for the interactive part of
FTP to either stdout or stderr. I'm not sure where it goes, but I can't
seem to get anything back out of the pipes once the task kicks off.
Here's a few parts of the code (this is lengthy, sorry):
This starts the FTP session when the user clicks a button in the UI...
- (void)start
{
// initialize arguments for CLI
NSMutableArray *theArguments = [NSMutableArray
arrayWithArray:[NSArray arrayWithObjects:@"-v",@"-d",
@"www.positivespinmedia.com", nil]];
// open a pipe for ping to send its output to
NSPipe *thePipe = [NSPipe pipe];
// open another pipe for the errors
NSPipe *errorPipe = [NSPipe pipe];
// open another pipe for the input (what I have to say to FTP)
NSPipe *inputPipe = [NSPipe pipe];
// make sure there isn't FTP task currently running
NSAssert( !theTask, @"Task already exists" );
// create the subprocess
theTask = [[NSTask alloc] init];
// set the subprocess to start a session
[theTask setLaunchPath:@"/usr/bin/ftp"];
[theTask setArguments:theArguments];
// point the output of the ping session to the pipe,
// and the error to the other pipe
[theTask setStandardOutput:thePipe];
[theTask setStandardError:errorPipe];
[theTask setStandardInput:inputPipe];
// launch ftp
[theTask launch];
// create file handles for the input, output, and error of the
session
theOutput = [[thePipe fileHandleForReading] retain];
theError = [[errorPipe fileHandleForReading] retain];
theInput = [[inputPipe fileHandleForWriting] retain];
// register myself as an observer for this pipe
// updates trigger output method
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(output:) name:NSFileHandleReadCompletionNotification
object:theOutput];
// register myself as an observer for the error pipe
// updates trigger output method
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(output:) name:NSFileHandleReadCompletionNotification
object:theError];
// put it in the background - don't hold UI hostage
[theOutput readInBackgroundAndNotify];
[theError readInBackgroundAndNotify];
// make the UI signal user - session in progress
// clean out the text field
[[theResponse textStorage] setAttributedString:[[[NSAttributedString
alloc] init] autorelease]];
// change button to stop
[connectButton setTitle:@"Stop"];
// this thing should be purring like a kitten
}
Once I click the button, I see (in a text field in the UI):
Connected to positivespinmedia.com.
220 ProFTPD 1.2.2rc1 Server (FTP) [positivespinmedia.com]
So... it does start the task and connect to the server properly. But
what I want to see is:
Connected to positivespinmedia.com.
220 ProFTPD 1.2.2rc1 Server (FTP) [positivespinmedia.com]
Name (www.positivespinmedia.com:johnp):
I'm missing that last line in my interface, despite the fact that it
does show up when running FTP from the command line. I would then enter
my username, password, and be on my way to a nice FTP session - thus my
wondering where FTP could be sending that last line to: it doesn't seem
to be showing up at stdout or stderr.
Here's the output method... as you can see, I am "resetting" the
notification mechanism for the filehandle...
- (void)output:(NSNotification *)aNotification
{
// get the data from the notification
NSData *theData = [[aNotification userInfo]
objectForKey:NSFileHandleNotificationDataItem];
NSString *theString = [[[NSString alloc] initWith
Data:theData
encoding:NSNEXTSTEPStringEncoding] autorelease];
// reset the notifier
[theOutput readInBackgroundAndNotify];
NSLog(@"output pipe triggered");
// put the stuff in the text field
[[theResponse textStorage]
appendAttributedString:[[[NSAttributedString alloc]
initWithString:theString attributes:[NSDictionary
dictionaryWithObjectsAndKeys:[NSFont userFontOfSize:12],
NSFontAttributeName, nil]] autorelease]];
// move the scroll if needed
[theResponse scrollRangeToVisible:NSMakeRange( [[theResponse
textStorage] length], 0 )];
}
Does anyone know where FTP is sending its output/error to, and how I can
pick it up? Or have any other ideas what might be wrong?
I appreciate any help anyone can offer!
John P.