In this version of the NetHopper architecture, we're explicitly going to deal with two kinds of Protocols: basic "cooperative" protocols which send and receive data for use by NetHopper and its plug-in modules, and "independent" protocols which, once launched, carry out an entire URL transaction without any further interaction with NetHopper or its plug-ins. Examples of cooperative Protocols include HTTP, FTP, and Gopher. It makes sense to view and download data from these Protocols using the standard NetHopper user interface and plug-ins. Examples of independent Protocols are rlogin, telnet, and mailto. It doesn't make much sense to "view" an interactive telnet session in the context of a web browser; it probably makes more sense to launch an independent telnet application to complete the user's request. In the case of mailto, it would be nice to launch an external mail application for composing and sending mail to the user given in the mailto URL.
An example of a borderline indpendent/cooperative case is NNTP (USENET news): because NNTP produces standard text files as content, it might make sense to view these documents within a web browser. However, there are certain kinds of context that an independent news reader can provide which are highly valuable. For instance, the news reader can keep track of the user's preferred newsgroups, already-read items within a newsgroup, kill-file article filtering preferences, and default NNTP server. For this reason we believe that it makes sense to launch an independent newsreader application to handle an NNTP URL. Note, however, that even an independent newsreader could still take advantage of the NetHopper plug-in architecture by utilizing NetHopper's data viewers, transaction handling facilities, and URL-launching facilities.
This API document will admittedly be cooperative Protocol-centric, because this is the more complicated case. It's assumed that most of the work of plugging in an independent protocol will revolve around registration.
Typically NetHopper will be told which protocol to use by its client. The client might request the URL "http://www.allpen.com", in which case the Transaction Manager knows to use the HTTP protocol. Currently we recognize and explicitly parse URLs for the following protocols:
Explicityly Recognized Protocols (in no particular order) | ||
Acronym or short name used in URL |
Coop or Ind? |
Description |
HTTP |
C |
HyperText Transfer Protocol |
FTP |
C |
File Transfer Protocol |
gopher |
C |
Gopher Protocol |
telnet |
I |
interactive Telnet Protocol |
tn3270 |
I |
interactive IBM 3270-terminal emulation session |
rlogin |
I |
interactive Remote Login Protocol |
mailto |
I |
send mail request |
WAIS |
C |
Wide Area Information Search Protocol |
NNTP or news |
I |
Net News Transfer Protocol for USENET news |
NFS |
C |
Network File System Protocol |
However, the NetHopper 3.0 plug-in architecture is designed to deal with Protocols it does not yet recognize and perhaps Protocols which do not yet exist.
Once NetHopper knows which protocol to use, it checks with the Registration Manager to see whether that Protocol is loaded. If it the Protocol is loaded, NetHopper launches that Protocol to complete the client's request.
NetHopper uses the MIME type returned by the Protocol to determine what to do with the content data. If the MIME type does not match the MIME type the client requested, NetHopper may attempt to convert the data into the type requested using a Data Converter.
To summarize, here's the Protocol life cycle:
Protocols need to register with the Registration Manager so that NetHopper and other plug-in applications can become aware of their presence.A Protocol needs to register by calling the following Registration Manager method:
RegWebProtocol(protocolSym, infoFrame);
This method registers a Protocol named by protocolSym with NetHopper's Protocol registry. Protocols must append their developer signature to end of the protocolSym to avoid collisions. For instance, the symbol '|HTTP:ALLPEN| is already reserved.
infoFrame contains the following slots:
codeFrame The frame which contains the executable Protocol code. It is this frame which must implement the Protocol methods described later in this chapter.
acronym A string or an array of strings which contains the protocol name or acronym as it commonly appears in URLs: for instance, "NNTP" and "news" might be registered by the same Protocol (as ["NNTP","news"]). "FTP" might be registered by another Protocol, "gopher" by another. Typically your Protocol should not register more than one acronym at once, unless there is more than one acronym for the exact same web protocol (as in NNTP/news).
operatingMode A symbol which indicates whether this Protocol prefers to operate in cooperative or independent mode. The currently allowed values are 'cooperative ,'independent, and 'both. If the protocol supports both cooperative and independent modes, it should use the 'both symbol.
independentLaunchFunc. If this Protocol can operate in the 'independent mode, this slot must contain a function that the Transaction Core can call in order to launch the Protocol in the indpendent mode. This function must accept a single parameter: a transaction request. Note that when this function is called, the Protocol will not have been Instantiated or Connected-- this is the only "hook" function that is called.
name This is a user-viewable string that might also be used to help the user pick an appropriate Protocol in some situations.
preferencesForm This slot should contain a reference to any preferences view template you might have for configuring your Protocol. This view might contain things like timeout and retry preferences. The default value is NIL, no preference view. If this slot exists and is non-NIL, this view will be displayed when the user picks "(name) Prefs" in the NetHopper preferences view. Note that this view template must use protoPrefsRollItem as its template and must have its overview slot set to the name of this prefs view as it should appear in the NetHopper prefs.
The Protocol also needs to unregister when it is removed:
UnRegWebProtocol(protocolSym);
This method tells NetHopper to remove the Protocol named by protocolSym from its Protocol registry.
Cooperative Protocols must provide several methods for client access: these are detailed in the following sections. Note that Independent Protocols need only implement the independentLaunchFunc as detailed in the previous section: they do not need to implement the Instantiate, Connect, &c. methods listed below.
This creates the Protocol.
Protocol:Instantiate()
Your protocol can do whatever it likes during this period. We suggest that you initialize any buffers you might need. You might also Instantiate an endpoint, for instance.
This method allows your Protocol client to set whether your Protocol should display any user input forms while trying to process a transaction. This allows your Protocol to collect missing or required information from a user (such as authentication info in the case of HTTP).
Protocol:setAllowUserInteraction(TRUE);
Your Protocol can exhibit whatever default behavior it wishes to, but we strongly suggest that Protocols leave this variable ON by default, so that the novice user will be able to enter passwords and such. Your Protocol's preferences form should provide a way to change the default value, however.
This method provides you with an inputStream from which to read bytes to be sent to the remote host. You can set up a read request on this inputStream, waiting for your client to provide you with bytes to be sent to the remote host. Some clients may never call this method: in this case, you have no content data to send to the remote host.
Note that this method implicitly provides your Protocol with MIME data typing information. You can call the inputStream GetMIMEDataType method to find out what kind of data is being provided.
This method provides you with an outputStream on which you can write bytes to send to your client. You can use this outputStream to take data you receive from the remote host and return it to your client.
Protocol:SetOutputStream(outStream);
Note that your Protocol needs to provide MIME typing information on this outputStream as soon as possible. For instance, after an HTTP Protocol has begun downloading data, it can determine what MIME type of data is being provided an call the outputStream's SetMIMEDataType with the appropriate type.
Note that your Protocol's SetOutputStream method may be called several times over the lifetime of your protocol (between when Instantiate and Dispose are called). Each time the call to SetOutputStream will likely be accompanied by a call to Connect. This is because your protocol may be reused for multiple transactions.
This method allows the Protocol client to tell you when, precisely, to connect to the remote server. This method should throw an exception if it fails?
Protocol:Connect(transactionReq, cbContext, cbSym);
Open a connection to the remote host given in the transactionRequest. This method should complete asynchronously and callback to the client when finished by doing this:
AddDeferredSend(cbContext, cbSym,[error]);
Note that the client might provide you with NIL values for cbContext and cbSym: you should handle this case by simple not performing the callback.
Note that Connect may be called several times over the lifetime of your Protocol. Each time it should be accompanied by a call to SetOutputStream and possibly SetInputStream. This is because your protocol may be reused for multiple transactions.
Gets the result transaction request frame for this connection. Note that this may vary from the transaction request frame passed in to Connect if the Protocol is "redirected".
transReqFrame := Protocol:GetActualTransaction();
This method must return a standard transaction request frame as detailed in the Transaction Core API documentation.
Gets the expriation date of the content.
int Protocol:getExpiration();
This method returns NIL if the expiration date of the content is not known. This method should return time in minutes, according to the standard Newton time format. Note that this method is mainly applicable to the HTTP protocol, but your Protocol may be able to provide this information as well.
Completely tear down the Protocol.
Protocol:Dispose();
After this method is called, no additional operations can be performed on this Protocol.