P4ClientApi.h #3

  • //
  • main/
  • guest/
  • tjuricek/
  • DocHub/
  • DocHub/
  • P4ClientApi.h
  • View
  • Commits
  • Open Download .zip Download (29 KB)
/*******************************************************************************

Copyright (c) 2001-2009, Perforce Software, Inc.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1.  Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

2.  Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*******************************************************************************/

/*===================================================================\
| Name       : P4ClientApi.H
|
| Author     : Michael Bishop <[email protected]>
|
| Description: Objective-C wrapper for the Perforce API.
\===================================================================*/

#import <CoreFoundation/CoreFoundation.h>


/*!
 \interface  P4ClientApi
 
 \brief P4ClientApi is an Objective-C wrapper around the
        <a href="http://www.perforce.com/perforce/doc.current/manuals/p4api/index.html">C++ ClientApi</a>.

 This documentation is a supplement to the more complete Perforce C++ API documentation
 available at: <a href="http://www.perforce.com/perforce/doc.current/manuals/p4api">http://www.perforce.com/perforce/doc.current/manuals/p4api</a>

 \see <a href="http://kbmain.perforce.com/AllPerforceApplications/PerforceCApi">Perforce C++ Client API Knowledge Base Articles</a>.


\section OVERVIEW Overview

To retrieve data from a Perforce server you must complete three tasks:
 -# Establish a connection
 -# Run one (or more) commands
 -# Disconnect
 
In addition to those tasks, there are a list of properties you may
set on the api instance to affect its operation.


\section SCHEDULING_ISSUES Scheduling Issues

The Perforce C++ API is a blocking API; that is, when a method is
executed to connect to, or retrieve data from the server, that method
does not return until the data has been sent and the command is finished.
This is usually unacceptable in a graphical user environment.

The Mac's solution to this is to create a network request and add it as
a source to the current RunLoop. The core Perforce C++ API has not been
written to support this mechanism directly. Instead you must execute the
client api requests in a separate thread so the current thread does not
block and send the results back to the originating thread.

Typically, this involves a lot of work to package mesages so they can be
sent across threads. Much care has been taken to handle as much of this
for you as possible. You are still responsible for scheduling the client
api request in a separate thread (to retain the most scheduling control)
but you can specify the thread to which the server results will be sent
and the return messages will be packaged up and sent to your delegate
in that thread.

Convenience methods to create NSInvocation objects for key client api
methods are provided for your use. You can add these invocations to an
NSOperationQueue and let the system schedule them, or you can ask the
invocation object itself to execute in another thread using NSObject's
<tt>performSelectorInBackground:withObject:</tt> (and variants).

Below is an example of blocking, and non-blocking ways of connecting to
the server:

BLOCKING:

\code
P4ClientApi * api = [[[P4ClientApi alloc] init] autorelease];
NSError * e;

// Your thread could block for a while if the server is not running
if (![api connectToPort:@"perforce:1666" withProtocol:nil error:&e] )
    return e;

... run the command
\endcode

NON-BLOCKING:
\code
P4ClientApi  * api = [[P4ClientApi alloc] init];

// Instead, of calling the method directly, create an invocation to be
// executed in another thread
api.callbackThread = [NSThread currentThread];
NSInvocation * invocation = [api invocationForConnectToPort:@"perforce:1666"
                                                    protocol:nil
                                                    delegate:self];

NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithInvocation:invocation];

// the operation queue will schedule the operation in another thread and return immediately
[operationQueue addOperation:operation];
[operation release];

...

-(void)clientApi:(P4ClientApi *) api
didFailToConnectWithError:(NSError*)s
{
    NSLog(@"failed to connect to %@", api.p4port);
    [api release];
}

-(void)clientApiDidConnect:(P4ClientApi*)api
{
... run the command on the client api
}
\endcode


\section HANDLING_ERRORS Error Handling

The Perforce Objective-C API wraps up native Perforce errors into an NSError
object. It does so in the following manner:

-# The domain of the NSError is set to: \p P4ErrorDomain.
-# The formatted message from the C++ Error object is passed in the NSError
    object as the \p localizedDescription.
-# The code of the first ErrorId in the C++ Error is placed into the NSError \p code.
    You can use this to compare with the included ErrorId instances in the C++ header files.
-# Additionally, you can see the pieces of the above ErrorId by looking in the userInfo field of
    the NSError and finding the NSValues for these keys:
    P4SubsystemErrorKey, P4SubCodeErrorKey, P4SeverityErrorKey, P4GenericErrorKey
*/

///  \mainpage  P4ClientApi
///  \copydoc   P4ClientApi

#import <Foundation/Foundation.h>

/// \brief  establishes the NSError domain for Perforce client errors
extern NSString * const P4ErrorDomain;

/// \brief  Key to retrieve the subsystem code of an Error from Perforce
extern NSString * const P4SubsystemErrorKey;

/// \brief  Key to retrieve the code (within a subsystem) of an Error from Perforce
extern NSString * const P4SubCodeErrorKey;

/// \brief  Key to retrieve the severity of an error from Perforce
extern NSString * const P4SeverityErrorKey;

/// \brief  Key to retrieve the generic code of an Error from Perforce
extern NSString * const P4GenericErrorKey;



/// \brief  Used to notify the server of the protocol level the client
///         understands
/// \see <a href="http://kb.perforce.com/P4dServerReference/ProtocolLevels/PerforceClientLevels">Perforce Protocol Levels</a>
extern NSString * const P4ProtocolVersion;

@protocol P4ClientApiConnectionDelegate;
@protocol P4ClientApiCommandDelegate;

@interface P4ClientApi : NSObject {

@private
    void *           _clientApi; // untyped to prevent C++ header inclusion

    void *           _currentClientUser; // untyped to prevent C++ header inclusion
    NSString       * _currentCommand;
    NSArray        * _currentArgs;
    id               _userInfo;
    NSThread       * _callbackThread;

    BOOL             _connected;
    NSString       * _ticketFilePath;
    NSString       * _programIdentifier;
    NSString       * _version;
    NSDictionary   * _requestedProtocol;
    BOOL             _prefersTaggedOutput;
    int              _rowScanningLimit;
    int              _tableLockingTimeLimit;
    int              _returnedResultsLimit;
}



/*! \name Connecting
          Use these to establish a connection to the server.
*/
//@{

/*!
    \brief  Establish a connection and prepare to run commands.

    Use this method to establish a connection to a Perforce server. It must be
    made before running any commands with runCommand:withArguments:delegate:
    
    The protocol is an NSDictionary of keys and values. The values can be of these types
    NSString, NSNumber, NSNull. They will all be converted to strings when
    sent to the server.
    
    \note  This method does not return until after a connection is made or unsuccessful.
        For unsucessful connections, this could last 5 seconds, blocking your
        event-loop. You may wish to instead call
        connectToPort:withProtocol:delegate: in another thread and
        have it return messages to your current thread.
    
    \param   port      a P4PORT value or \p nil to use the default.
    \param   requestedProtocol  A dictionary of protocol values to configure the connection.
                                You may pass \p nil if you don't have a specific protocol
                                requirement.
    \param   error     a pointer to an NSError pointer or \p nil
                       (see \ref HANDLING_ERRORS)
    \result  YES       if the connection was completed
    \result  NO        if the connection could not be made. An error will be returned in
                       \p which the caller must retain.
    
    \note   Internally, this is equivalent to calling
            <tt>ClientApi::SetPort();
                ClientApi::SetProtocol();
                ClientApi::Init();</tt>
    
    \see connectToPort:withProtocol:delegate:
    \see ClientApi::SetPort()
    \see ClientApi::SetProtocol()
    \see ClientApi::Init()
*/
-(BOOL)connectToPort:(NSString*)port
        withProtocol:(NSDictionary*)requestedProtocol
               error:(NSError **)error;


/*!
    \brief  Establish a connection and prepare to run commands.

    Use this method to establish a connection to a Perforce server. It must be
    made before running any commands with runCommand:withArguments:delegate:
    
    The protocol is an NSDictionary of keys and values. The values can be of these types
    NSString, NSNumber, NSNull. They will all be converted to strings when
    sent to the server.
    
    \note  This method does not return until after a connection is made or unsuccessful.
        For unsucessful connections, this could last 5 seconds, blocking your
        event-loop. You may wish to instead call it in another thread and
        have it return messages in your current thread to your delegate.

    \param   port      a P4PORT value or \p nil to use the default.
    \param   requestedProtocol  A dictionary of protocol values to configure the connection.
                                You may pass \p nil if you don't have a specific protocol
                                requirement.
    \param   delegate  a delegate object that is used to process messages from the server.
                       It is not retained.

    \note   Internally, this is equivalent to calling
            <tt>ClientApi::SetPort();
                ClientApi::SetProtocol();
                ClientApi::Init();</tt>

    \see connectToPort:withProtocol:error:
    \see ClientApi::SetPort()
    \see ClientApi::SetProtocol()
    \see ClientApi::Init()
*/
-(void)connectToPort:(NSString*)port
        withProtocol:(NSDictionary*)requestedProtocol
            delegate:(id<P4ClientApiConnectionDelegate>)delegate;

/*! \brief  Convenience method to create an invocation for use in non-blocking calls.

    Use this method to create an NSInvocation that can be called in another
    thread or added to an NSOperationQueue as an NSInvocationOperation.

    The protocol is an NSDictionary of keys and values. The values can be of these types
    NSString, NSNumber, NSNull. They will all be converted to strings when
    sent to the server.
    
    \note  as is consistent with NSInvocations, the arguments are not
           retained by default. Creating an NSInvocationOperation will retain
           the arguments automatically.
    
    \param   port      a P4PORT value or \p nil to use the default.
    \param   requestedProtocol  A dictionary of protocol values to configure the connection.
                                You may pass \p nil if you don't have a specific protocol
                                requirement.
    \param   delegate  a delegate object that is used to process messages from the server.

    \see connectToPort:withProtocol:delegate:
*/

-(NSInvocation*)invocationForConnectToPort:(NSString*)port
                               withProtocol:(NSDictionary*)requestedProtocol
                                   delegate:(id<P4ClientApiConnectionDelegate>)delegate;
// @}


/*! \brief  The port connected to in connectToPort:withProtocol:error:
    \note   It could be a Bonjour name.
    \see    ClientApi::GetPort()
*/
@property(readonly, copy)    NSString * p4port;

/*! \brief  The current user name.
    \see    ClientApi::Set/GetUser()
*/
@property(readwrite, copy)   NSString * user;

/*! \brief  The current client name.
    \see    ClientApi::Set/GetClient()
*/
@property(readwrite, copy)   NSString * client;

/*! \brief  The name of the character set used for translation between
            the server and the client.

    This is required field when talking to a server in unicode mode and required to be
    \p nil when communicating with a non-unicode server. Perforce recommends
    the value of \p utf8 with Mac OS X-based clients.
    
    For more information on using the P4API with unicode-enabled servers, see
    <a href="http://kbmain.perforce.com/P4dServerReference/Internationalization/UnicodeAndP4..sAndAnswers">Unicode and P4API</a>
    
    \note   This calls ClientApi::SetTrans() before establishing a connection
*/
@property(readwrite, copy)   NSString * charset;

/*! \brief  The current working directory.
    \see    ClientApi::Set/GetCwd()
*/
@property(readwrite, copy)   NSString * currentWorkingDirectory;

/*! \brief  The password sent to the server for this connection.
    \see    ClientApi::Set/GetPassword()
*/
@property(readwrite, copy)   NSString * password;

/*! \brief  Indicates to the server that the client prefers data to be returned via
            the clientApi:didReceiveTaggedResponse: method of the command delegate.
            
    This is \p YES by default.

*/
@property(readwrite, assign)   BOOL prefersTaggedOutput;

/*! \brief  The name of this host. Unless set explicitly may not be available until
            after connecting to the server.
            
    \see    ClientApi::Set/GetHost()
*/
@property(readwrite, copy)   NSString * hostname;

/*! \brief  The location of the user's ticketfile
    \note   This must be the full path to the file and not a directory.
    \see    ClientApi::Set/GetTicketFile()
*/
@property(readwrite, copy)   NSString * ticketFilePath;

/*! \brief  The identifier of the application program which will show up in
            logging viewed with the <tt>p4 monitor</tt> command and in
            server log output.
            
    It's "P4V" below.

\code
45381 P4V/v60   10.0.105.2194   R joeuser      joeuser      04:01:53 IDLE none
\endcode

    \note   Unlike the C++ API, you can set this at anytime.
    \see    ClientApi::Set/GetProg()
*/
@property(readwrite, copy)   NSString * programIdentifier;

/*! \brief  The version of the application program which will show up in
            logging viewed with the <tt>p4 monitor</tt> command and in
            server log output.
            
    When not set, it defaults to the protocol level of the Client API libraries.
     It's "v60" below.
            
\code
45381 P4V/v60   10.0.105.2194   R joeuser      joeuser      04:01:53 IDLE none
\endcode

    \note   Unlike the C++ API, you can set this at anytime.
    \see    ClientApi::Set/GetProg()
*/
@property(readwrite, copy)   NSString * version;

/*! \brief  The userInfo object set on the api object as context when connecting
            or running commands.
    \see    runCommand:withArguments:delegate:
*/
@property(readwrite, retain)   id userInfo;

/*! \brief  The thread in which the client api will send back its responses.
            This is useful when executing the client api in another thread
            and sending back responses to the main thread for asynchronous
            operation.
            
            When the value is \p nil, the api object will call back to whatever
            the currently executing thread is.
            
            It's \p nil by default
*/
@property(readwrite, retain)   NSThread * callbackThread;

/*! \brief  The filename used when Perforce searches for configuration files
            from which to retrieve default values.
    \see    ClientApi::GetConfig()
*/
@property(readonly)          NSString * configurationFilename;

/*! \brief  The state of the connection. If the connection was dropped or
            otherwise disconnected, this will return NO.
    \see    ClientApi::Dropped()
*/
@property(readonly)          BOOL       connected;

/*! \name Executing commands
          Once you have established a connection to the server,
          you can use these to execute commands.
*/
//@{


/*! \brief  Executes a command on the Perforce server.

    Use this method to actually execute a command on the Perforce server.
    Results are returned via the delegate.
    
    \note  This method does not return until after after the server has completely processed
        the command and has sent clientApiDidFinishCommand: to your delegate. Because
        this stops the current RunLoop from continuing, you may find it desirable
        to make this call in another thread and have the server send messages back
        to the current thread, allowing the RunLoop to continue.
    
    \note  Before making thing call, you must have a connection established through
        connectToPort:withProtocol:error:
    
    \attention  This method is not thread-safe. If you are scheduling this
                call by scheduling invocation objects, you must make sure
                that this call returns before the next invocation is called.
                You can do this by creating a separate NSOperationQueue per
                client api instance and making sure the queue's
                <tt>maxConcurrentOperationCount</tt> equals 1
                before queuing your invocation objects in it.
    
    \param  command   the command you want to run (eg: "sync").
    \param  args      An array of arguments to be sent with the command. You may pass \p nil if the
                      \p command doesn't require arguments to execute.
    \param  delegate  a delegate object that is used to process messages from the server.
                      It is not retained.

    \note   Internally, this is equivalent to calling
            <tt>ClientApi::SetArgs();
                ClientApi::RunCmd();</tt>
*/
-(void)runCommand:(NSString *)command
    withArguments:(NSArray*)args
         delegate:(id<P4ClientApiCommandDelegate>)delegate;

/*! \brief  Convenience method to create an invocation for use in non-blocking calls.

    Use this method to create an NSInvocation that can be called in another
    thread or added to an NSOperationQueue as an NSInvocationOperation.

    \note  as is consistent with NSInvocations, the arguments are not
           retained by default. Creating an NSInvocationOperation will retain
           the arguments automatically.
    
    \param  command   the command you want to run (eg: "sync").
    \param  args      An array of arguments to be sent with the command. You may pass \p nil if the
                      \p command doesn't require arguments to execute.
    \param  delegate  a delegate object that is used to process messages from the server.

    \see runCommand:withArguments:delegate:
*/
-(NSInvocation*)invocationForRunCommand:(NSString *)command
                          withArguments:(NSArray*)args
                               delegate:(id<P4ClientApiCommandDelegate>)delegate;

//@}

/*! \name Advanced Performance Options
          Use these to control or limit server calculation or output.
*/
//@{

/*! \brief  Limits the rows of data considered and prevents the server from
            making large-scale scans.
            
            Assigning a value of 0 (the default) has no effect.
    \see    http://kb.perforce.com/AdminTasks/PerformanceTuning/MaximizingPe..Performance
    \see    p4 help maxscanrows
*/
@property(readwrite, assign) int rowScanningLimit;

/*! \brief  Limits the amount of time spent during data scans to prevent the
            server from locking tables for too long.
            
            Assigning a value of 0 (the default) has no effect.
    \see    http://kb.perforce.com/AdminTasks/PerformanceTuning/MaximizingPe..Performance
    \see    p4 help maxlocktime
*/
@property(readwrite, assign) int tableLockingTimeLimit;

/*! \brief  Limits the rows of resulting data buffered and prevents the server
            from using excessive memory.
            
            Assigning a value of 0 (the default) has no effect.
    \see    http://kb.perforce.com/AdminTasks/PerformanceTuning/MaximizingPe..Performance
    \see    p4 help maxresults
*/
@property(readwrite, assign) int returnedResultsLimit;


//@}

/*! \name While running commands...
          In your P4ClientApiCommandDelegate methods, you can call these
          to retrieve the items passed to <tt>runCommand:withArguments:delegate:</tt>...
          
*/
//@{
/*! \brief  The command that the client api instance is executing.
    \see    runCommand:withArguments:delegate:
*/
@property(readonly, copy) NSString * currentCommand;

/*! \brief  The arguments for the currently executing command.
    \see    runCommand:withArguments:delegate:
*/
@property(readonly, copy) NSArray *  currentArguments;

//@}




/*! \name Disconnecting
          These terminate your connection to the server, reporting
          any residual errors.
*/
//@{

/*! \brief  Disconnects from the server and reports disconnection errors.

    \param   error     a pointer to an NSError or \p nil
                       (see \ref HANDLING_ERRORS)
    \result  YES       if an error was raised
    \result  NO        if the disconnection has no errors.
    \see ClientApi::Final()
*/
-(BOOL)disconnect:(NSError **)error;

/*! \brief  Disconnects from the server and reports disconnection errors.

    \param   delegate  a delegate object that is used to process messages from the server.
                       It is not retained.
    \see ClientApi::Final()
*/
-(void)disconnectWithDelegate:(id<P4ClientApiConnectionDelegate>)delegate;

/*! \brief  Convenience method to create an invocation for use in non-blocking calls.

    Use this method to create an NSInvocation that can be called in another
    thread or added to an NSOperationQueue as an NSInvocationOperation.

    \note  as is consistent with NSInvocations, the arguments are not
           retained by default. Creating an NSInvocationOperation will retain
           the arguments automatically.
    
    \param   delegate  a delegate object that is used to process messages from the server.

    \see disconnectWithDelegate:
*/
-(NSInvocation*)invocationForDisconnectWithDelegate:(id<P4ClientApiConnectionDelegate>)delegate;
//@}


/*! \name Setting and inspecting the server protocol
          You can request specific protocol parameters when calling
          connectToPort:withProtocol:error:. After running
          a command, the server will also send back additional parameters
          about the connection.
*/
//@{
/*!
    \brief  The protocol dictionary passed in to connectToPort:withProtocol:...

    \see connectToPort:withProtocol:error:
*/
@property(readonly, copy) NSDictionary * requestedProtocol;

/*!
    \brief  The protocol parameters (as a property) containing information about
            communication between the server and client.
    
    After making a call to runCommand:withArguments:delegate:,
    the server sends a dictionary of additional protocol variables back to the
    client with additional information about the communication between server
    and client.

    \note   This is \b different from the dictionary passed in to connectToPort:withProtocol:error:
    \see ClientApi::GetProtocol()
*/
-(NSObject*)serverProtocolValueForKey:(NSString*)key;
//@}


@end


/*!
 \protocol  P4ClientApiConnectionDelegate
 
 \brief     Implement this in a delegate when establishing a non-blocking
            connection to a Perforce server.
 
 connectToPort:withProtocol:error: is a blocking
 call that will not return until a connection is made, or fails. The
 timeout is roughly 5 seconds. For this reason, you are encouraged to
 implement this protocol and make your connection in another thread.
 
 */
@protocol P4ClientApiConnectionDelegate <NSObject>

@optional
/*!
    \brief  Called on your delegate when the client has sucessfully
            established a connection. You may now start running
            commands with
            runCommand:withArguments:delegate:

    \param  api    the client api instance calling this method.
*/
-(void)clientApiDidConnect:(P4ClientApi*)api;

/*!
    \brief  Called on your delegate when the client was not able to establish
            a connection. The client may wait for about 5 seconds before
            it calls your delegate with this method.
            
    \param  api    the client api instance calling this method.
    \param  error  the error message which you can report to the user.
                   (see \ref HANDLING_ERRORS)
*/
-(void)clientApi:(P4ClientApi*)api didFailToConnectWithError:(NSError*)error;

/*!
    \brief  Called on your delegate when the client disconnects from the
            server (by calling disconnectWithDelegate:).
            
    \param  api    the client api instance calling this method.
    \param  error  the residual errors from the server
                   (see \ref HANDLING_ERRORS)
*/
-(void)clientApi:(P4ClientApi*)api didDisconnectWithError:(NSError *)error;

@end


/*!
 \protocol  P4ClientApiCommandDelegate
 
 \brief     Implement this to receieve messages from the Perforce server as a
            result of calling
            runCommand:withArguments:delegate: on a
            P4ClientApi instance.
 
 Each method returns a different type of response
 depending on the executing command and the configuration of the
 P4ClientApi instance. It is closest to the ClientUser class in the C++ API.
 
 \note  If a message is not implemented by your delegate class, the
        ClientUser behavior is executed by default. That behavior is what
        the p4 command-line CLI uses.
 
 Each of of these methods has an analagous callback in the C++ API. They
 are documented with each method.
 
 */
@protocol P4ClientApiCommandDelegate <NSObject>

@optional

/*!
    \brief  Called on your delegate when the client was not able to establish
            a connection. The client may wait for about 5 seconds before
            it calls your delegate with this method.
            
    \param  api    the client api instance calling this method.
    \param  error  the error message which you can report to user.
                   (see \ref HANDLING_ERRORS)
    \see ClientUser::OutputError
*/
-(void)didReceiveError:(NSError*)error;


/*!
    \brief  Called on your delegate by the server during most Perforce
            commands; its most common use is to display listings of information
            about files.

    \note   The messages from the server in this call are "simple" because
            they are meant to be sent directly to the console and do not
            include a code for the message.

    \param  api      the client api instance calling this method.
    \param  message  the printable message from the server
    \param  level    the indentation "level" of the output
    
    \see ClientUser::OutputInfo(
*/
-(void)didReceiveSimpleServerMessage:(NSString*)message level:(char)level;


/*!
    \brief  Called on your delegate when the server has formatted output.
    
    This is much more useful than a simple message. Normally, only the results
    of an "fstat" command come through this method, but you can get many more
    commands to output in this way, by setting \p prefersTaggedOutput to
    YES on the P4ClientApi instance.
\code
api.prefersTaggedOutput = YES;
\endcode            
    \param  api      the client api instance calling this method.
    \param  response the dictionary containin a structured response.
    \see ClientUser::OutputStat
*/
-(void)didReceiveTaggedResponse:(NSDictionary*)response;


/*!
    \brief  Called on your delegate typically as a result of a "print" command
            on a binary file.

    \param  api   the client api instance calling this method.
    \param  data  the binary data from the server
    
    \see ClientUser::OutputBinary
*/
-(void)didReceiveBinaryContent:(NSData*)data;


/*!
    \brief  Called on your delegate typically as a result of a "print" command
            on a text file.

    \param  api   the client api instance calling this method.
    \param  text  the text data from the server
    
    \see ClientUser::OutputText(
*/
-(void)didReceiveTextContent:(NSString*)text;


/*!
    \brief  Called on your delegate when the server has finished processing a
            command.

    \param  api    the client api instance calling this method.
    \see ClientUser::Finished()
*/
-(void)clientApiDidFinishCommand;

/*!
    \brief Called on your delegate to provide input text to the underlying API
 
    \see ClientUser::InputText(StrBuf*, Error*)
*/
-(NSString*)getInputText;

@end

# Change User Description Committed
#3 9475 tjuricek Set up the positive workflow for AddPerforceController to get a login token.

This required adding another couple of methods to provide input to the p4api (which were surprisingly absent from the earlier system).
#2 9397 tjuricek Basic p4d interaction with p4 using Swift
#1 9229 tjuricek Basic project code for a prototype

Assumes p4api library is available at /usr/local/p4api