[ First ]  [ Previous ]  [ Next ]  [ Last ]  [ Manuals ]

 

Chapter 5.

 

Internet Programming in PowerPlant



This chapter discusses how to use the PowerPlant Internet classes to create a variety of Internet-enabled programs.


Introduction to Internet Programming in PowerPlant

The global collection of networks known as the Internet has grown in size at a staggering rate. Businesses, schools, governments, and individuals are making use of the interconnected nature of the Internet to conduct their daily affairs. Many tools help in these endeavors: electronic mail, the World Wide Web, and file transfer being but a few.

The primary networking protocol stack used on the Internet is the collection of protocols known as Transmission Control Protocol/Internet Protocol (TCP/IP). On top of this foundation exists a large collection of mostly standardized, task-specific protocols. These protocols are specified in the Request For Comment (RFC) documents which are the definitive source for implementation details.

Several of these task-specific protocols have been implemented in the PowerPlant library of classes. Electronic mail is represented with classes covering the Simple Mail Transport Protocol (SMTP) for sending messages to mail servers, and the Post Office Protocol version 3 (POP3) for retrieving messages from mail servers. The main protocol of the World Wide Web, the Hierarchical Text Transfer Protocol (HTTP), is provided. File transfer is included with the File Transfer Protocol (FTP) classes. Finally, a collection of helper classes exist to make preparing and interpreting data sent by these protocols simpler to code.

The PowerPlant implementations of these classes are built on top of the PowerPlant network classes documented elsewhere in this manual. By using the network classes as the foundation, the Internet classes work well with either MacTCP or Open Transport installed on the target Macintosh.


WARNING!

The Internet classes make use of the threaded version of the PowerPlant network classes. You will need to check that the Thread Manager is installed on the host computer for your application to work properly.


This chapter's topics include:


Where to Learn More About Internet Protocols

The Internet is always changing, and even the protocols that are described in this chapter are constantly evolving. This chapter shows you how to make use of the protocol classes, but does not teach you the intricacies and nuances of the protocols themselves. For that, we recommend that you review the ultimate resource for the protocols, the Request For Comment (RFC) documents. RFCs describe in great depth how protocols function, and they explain some of the implementation details that are useful to understand when writing Internet software.

This chapter's descriptions of the PowerPlant Internet classes and their application assumes that you have a basic familiarity with Internet protocols and creating networking software. You should also understand the fundamentals of using Mac OS Threads and the PowerPlant classes that support them. There are many issues that you must consider when implementing a robust communications program, and experience is the best guide. There are many other books and resources that you can read to learn about Internet protocols and programming.

Comer, Douglas E. Internetworking with TCP/IP, Volume 1, Principles, Protocols, and Architecture. Prentice Hall.

Comer, Douglas E. Internetworking with TCP/IP, Volume 3, Client-Server Programming and Applications. Prentice Hall.

Stevens, W. Richard. TCP/IP Illustrated, Volume 1-3. Addison Wesley.

Internet Engineering Task Force at http://www.ietf.cnri.reston.va.us/ (for RFCs)


Software Requirements

The PowerPlant Internet classes require several pieces of system software. MacTCP (also known as "classic networking") or Open Transport must be installed and properly configured for the Internet classes to operate. If you want to be able to connect with other machines, the computer on which your application runs must also be connected to a network that supports TCP/IP. The Internet classes will work just fine regardless of whether you are connected via Ethernet, a serial connection using Point to Point Protocol (PPP), or some other physical connection. However, you may want to adjust the operation of your software depending on the performance of the link.

Additionally, the Thread Manager must be installed if it is not already part of the version of the Mac OS running on the target computer.


Internet Programming Strategy

The PowerPlant Internet classes implement a general foundation that easily supports Internet protocols modeled on a command and response scheme. On top of this foundation is support for some of the most common Internet standard protocols. The different protocol APIs provide a simple interface that allows you to concentrate on the operation you wish to complete, not the underlying details.


TIP

Depending on your programming situation, you may want to use the Internet classes apart from the rest of PowerPlant. The Internet classes currently require the following other components of the PowerPlant library: the Internet Class hierarchy, the Network hierarchy, the Thread classes, LPeriodical, LArray, UMemoryMgr utilities, LBroadcaster, LListener, and the ANSI library.


This section discusses the following topics:


Generic Internet Protocol Interface

Many Internet protocols follow the same general pattern in how they communicate between two computers. The connection is opened by the sending computer, the receiver acknowledges the connection, then the sender starts writing command sequences with optional data one at a time. The receiver accepts each command and replies with a response code and optional data.

The Internet classes implement this generic behavior with two base classes:

LInternetProtocol is used to create the connection between your program and the destination program on a remote computer. This base class provides the infrastructure for protocols that follow the command and response model.

LInternetResponse embodies the typical format of a response that you will receive from the remote program when it acknowledges your program's commands.


Specific Internet Protocol Interfaces

The PowerPlant Internet classes implement several of the more popular Internet protocols in use today. These classes all follow the general command and response model of communication. The classes currently implemented include:

LSMTPConnection and LSMTPResponse implement the Simple Mail Transport Protocol (SMTP) which is the primary transmission protocol for electronic mail messages. The classes implement the basic command set of the SMTP specification (RFC822).

LPOP3Connection and LPOP3Response implement the Post Office Protocol version 3 (POP3). This set of classes can be used to retrieve mail from a compliant mail server. The classes implement some of the optional POP3 commands such as TOP and APOP, an alternate authentication method (RFC1725).

LHTTPConnection and LHTTPResponse implement the Hierarchical Text Transport Protocol (HTTP). HTTP is used most frequently for communication with World Wide Web (WWW) servers. These classes give you all of the necessary tools for using the basic features of HTTP version 1 including the GET, POST, and HEAD methods (IETF draft 4-see RFC web site).

LFTPConnection and LFTPResponse implement the File Transfer Protocol. These classes allow you to send, retrieve, and manipulate files as described in the FTP specification (RFC959).


NOTE

This chapter does not describe the inner workings of the various Internet protocols supported by the PowerPlant Internet class library. The ultimate source of information for these protocols can be found in their specifications in the Request For Comments documents which can be found at the address given earlier in this chapter.



Internet Messages

Some Internet protocols, such as SMTP and HTTP, require that data be sent in a special format (RFC822). These encapsulated messages are composed of two parts:

1. a collection of headers which provide protocol specific information regarding the handling of the data, and

2. a message body that contains your data (perhaps encoded in a certain way).

The PowerPlant Internet classes support this concept with a collection of classes that implement messages:

¯ LMailMessage

¯ LHTTPMessage

LHeaderField LHeaderFieldList LMailMessageList

LInternetMessage is a base class that implements the basic behavior of an RFC822 message. This class provides the ability to easily manipulate the headers and body of a message.

LMailMessage is a message for electronic mail and is used by both SMTP and POP3. It provides a simple interface for accessing mail specific header fields. The class supports simple MIME enhancements including multipart messages.


NOTE

MIME stands for Multipurpose Internet Mail Extensions (RFC1521) and is a specification for a set of message headers that describe a variety of enhanced message body types and content. MIME messages can include special encodings, multiple parts, binary information, etc.. HTTP 1.0 is not fully MIME compliant. HTTP uses the MIME headers to determine the content type of the message, but only supports a small subset of the available types at this time.


LHTTPMessage is a message specifically formatted for HTTP. It provides a simple interface to access header fields unique to the protocol. The class implements the minimal MIME support required by the HTTP specification.

LHeaderField is a utility class used by the message classes to store and construct RFC822 style header fields.

LHeaderFieldList is another utility class that maintains an array of header fields during the construction of a message.

LMailMessageList is a utility class that maintains an array of pointers to LMailMessage objects.


General Utilities

The PowerPlant Internet classes make use of a number of general utility functions and classes:

LDynamicBuffer is used throughout the Internet classes to provide storage buffers that can grow or shrink whenever you change their contents.

UInternet contains a number of useful utility functions that includes routines to encode data for a variety of different protocols.

MD5 is a collection of C functions that implement the MD5 message digest encryption algorithm.

UUEncode is a collection of C functions that implement the uuencode character encoding algorithm (based on RFC1113).


NOTE

The details of the different encoding routines are beyond the scope of this chapter. You should refer to a standard text on character encoding and encryption for more details.



Strategic Summary

Depending on which protocol you choose to use in your program, there are really two levels of detail you can explore within the PowerPlant Internet classes:

The first choice gives you "fire and forget" functionality for the most common tasks in each protocol. You should use this option when you want to add basic Internet functionality to your program and don't need fine control over the connection.

The second choice is more appropriate if you need a high degree of control over the flow of the session. One example might be when you are implementing a full client application for your chosen protocol. In this kind of program, you want to manage the transaction each step of the way. Adding an Internet protocol to your program is still a relatively simple procedure. You open a connection to the desired remote computer, alternate between sending commands with optional data and receiving their responses, and finally closing down the connection.


Internet Classes

Before reading this section, you should have a basic understanding of the operation of the PowerPlant Internet class library. You should read "Internet Programming Strategy" to review the general concepts of the library. In this section, we will take a closer look at the primary classes, and describe their more important functions and behaviors. Figure 5.1 is an illustration of the classes that we will cover and their relationship to one another.

The gray bar indicates an abstract class.


NOTE

These classes were designed so that you can make use of them with a minimal amount of PowerPlant. See "Internet Programming Strategy" for a list of dependencies if you wish to use the Internet classes in non-PowerPlant code.


 

The primary Internet classes:

This section discusses the following classes:

¯ LSMTPConnection

¯ LPOP3Connection

¯ LHTTPConnection

¯ LFTPConnection

LInternetResponse

¯ LSMTPResponse

¯ LPOP3Response

¯ LHTTPResponse

¯ LFTPResponse

LInternetMessage

¯ LMailMessage

¯ LHTTPMessage

LDynamicBuffer LHeaderField Other Classes

LInternetProtocol

LInternetProtocol is the foundation on which PowerPlant's Internet functionality is based. It is the base class for implementing those protocols that follow a command and response model of communication. It is a subclass of LListener so that it may capture networking events generated from its LTCPEndpoint object. LInternetProtocol also inherits from LBroadcaster and uses this functionality to provide a progress notification mechanism for clients of the protocol object.

LInternetProtocol is itself relatively simple, providing the basic tools to implement specific protocols. This description outlines the primary member functions you are likely to use in your code. For more details, refer to the PowerPlant source code.

LInternetProtocol's data members are all protected from direct access, you should make use of the provided accessor functions if you need to get or change values.


NOTE

By making use of accessor functions to manipulate shielded data, you protect your code from being compromised by future changes in the underlying PowerPlant Internet class architecture.


Important LInternetProtocol functions:

 

Function
Purpose
LInternetProtocol()  
constructor, you must supply a reference to the thread in which the protocol is being implemented  
Connection Management  
Connect()  
manually opens a connection to remote system addressed via a DNS format address  
Disconnect()  
manually closes the connection to remote system  
Abort()  
stops the network operation  
Data Transfer  
 
SendData()  
sends data buffer in SendSize chunks, reporting progress periodically  
Data Buffer Management  
SetSendSize()  
sets the size chunks SendData() will break a buffer into for transmission  
GetSendSize()  
returns chunk size  
Thread Management  
 
SetThread()  
sets the thread to yield to on data arrival  
Progress Notification  
BroadcastProgress()  
sends a coded message and SProgressMessage buffer to any LListeners linked to the protocol object  
SetMinBroadcastTicks()  
sets the frequency of progress notification in ticks  
GetMinBroadcastTicks()  
gets the progress notification in ticks  

LInternetProtocol is a base class that handles all of the details of the network connection for you. Perhaps its most helpful trait is that it hides (and handles) interaction with the lower level network classes. It creates an LTCPEndpoint, handles addressing, binding, connections, data transfer, and other minutia.

LInternetProtocol doesn't implement a specific protocol, but rather provides the basic tools with which HTTP, SMTP, POP3, and other command and response protocols can be constructed. You will rarely need to instantiate a plain LInternetProtocol object.

The protocols written on top of LInternetProtocol have many convenience functions that are particular to the individual protocols. You will most frequently make use of the convenience functions and not need to worry about the functions implemented at this level. One specific example is the connection management functions. The wrapper functions are simple interfaces in the protocols detailed below that handle the opening and closing of connections for you.

An important aspect of this class is that LInternetProtocol and its derivatives are intended to be created from within an LThread object. The standard procedure is to create a thread for each instance of the protocol (often for each separate connection), and within the thread's body, create the protocol object. See the code exercises below for an example.


NOTE

The Internet classes make heavy use of threading. You should be familiar with Mac OS threads in general, and the PowerPlant LThread class hierarchy in particular. See the chapter on Threads for more information about using threads in your projects.


A typical scenario for using a connection can be summarized like this:


LSMTPConnection

LSMTPConnection implements the Simple Mail Transport Protocol (SMTP). Internet clients usually use SMTP to send electronic mail messages to SMTP aware servers. The current PowerPlant implementation of SMTP is designed with this behavior in mind. LSMTPConnection is a very simple class, providing member functions that wrap the process of sending mail messages into one function call.

Important LSMTPConnection functions:

 

Function
Purpose
LSMTPConnection()  
constructor  
Connection Management  
Connect()  
defaults to port 25  
Protocol Commands  
SendOneMessage()  
wrapper functions that sends one LMailMessage object, defaults to port 25  
SendMessages()  
wrapper function that sends one or more LMailMessages provided in an LMailMessageList array object, defaults to port 25  

The protocol command functions SendMessages() and SendOneMessage() handle the opening and closing of a connection. You will rarely need to use the Connect() function.

SMTP defaults to TCP port 25, and if you do not specify otherwise, LSMTPConnection will use the standard port number. LSMTPConnection implements the basic SMTP protocol as defined in RFC821.


NOTE

SMTP has been extended in later RFCs to provide more advanced and efficient data handling (SMTP Service Extension--RFC1651). LSMTPConnection does not currently support these extensions.



LPOP3Connection

LPOP3Connection implements the Post Office Protocol, version 3 (POP3). POP3 is used to retrieve electronic mail messages from a compliant mail server. It offers authenticated access to a remote mail box and has the ability to retrieve all or portions of a mail drop.

When implementing a mail retrieval client, you will often want more functionality than simply gathering mail messages from a remote host. You may want to retrieve some messages and leave others on the server. You may want to provide your user with house-keeping functionality, such as the ability to just check mail message headers, or to delete mail without downloading messages first. LPOP3Connection provides both simple to use wrapper functions for retrieving mail and functions for more detailed access to the POP3 command set.

LPOP3Connection multiply inherits from both LInternetProtocol and LPeriodical.

Important LPOP3Connection functions:

 

Function
Purpose
LPOP3Connection()  
constructor  
Connection Management  
Connect()  
makes a connection with supplied authentication credentials, defaults to port 110  
SpendTime()  
periodically calls NoopServer() to maintain connection  
Protocol Commands  
GetOneMessage()  
wrapper function for connecting, authenticating, and collecting one LMailMessage from the designated mail box and identified by a message number, defaults to port 110  
GetMessages()  
wrapper function for connecting, authenticating, and collecting all messages in the designated mail box and returning them in an LMailMessageList array of LMailMessages, defaults to port 110  
GetHeaders()  
wrapper function for connecting, authenticating, and collecting all message headers in the designated mail box and returning them in an LMailMessageList array of LMailMessages, defaults to port 110
CollectAllMessages()  
gets all messages from the open connection and places them in an LMailMessageList array of LMailMessages  
CollectAllHeaders()  
gets all headers from the open connection and places them in an LMailMessageList array of LMailMessages  
GetMailMessage()  
retrieves one message identified by its session mail box message number  
GetTop()  
retrieves one header identified by its session mail box message number  
DoList()  
retrieves an LList of POP3ListElem structures culled from the results of the LIST command  
DoUIDL()  
retrieves an LList of POP3ListElem structures culled from the results of the UIDL command  
DeleteMessage()  
removes the message identified by its session mail box message number from the remote computer  
NoopServer()  
sends a NOOP command to the remote computer  
ResetServer()  
sends a RSET command to the remote computer  
ServerStatus()  
retrieves the mail box message count and size from the server  
SendQUIT()  
sends a QUIT command to the remote computer  

The protocol command functions GetOneMessage(), GetMessages(), and GetHeaders() are wrapper functions that handle the opening and closing of a connection. If the connection is already open, they will not automatically close it. Likewise, if the connection is closed, the connection will be closed on completion of the function.

The lower level protocol command functions require that the connection be open and the user be authenticated. If this is not true, the functions will throw exceptions.

Many of the LPOP3Connection member functions require a message number as one of their parameters. As described in the POP3 specification, message numbers do not uniquely identify a mail message across different connections to the mail server. Only rely on a number during a single session. If you need a unique identifier for a message, try to use the UIDL results to match the unique id to the current message number. See the RFC for details.

POP3 defaults to TCP port 110, and all connection related functions will use the standard port unless you supply another port number. LPOP3Connection implements the standard POP3 version as described in RFC1725. It includes implementations of the optional commands UIDL, TOP, and APOP. Most, but not all, POP3 servers support this optional command set. Your code should prepare for the worst. Be especially careful when using the header related functions-they use the TOP command, which is often not implemented on older POP3 servers-and be sure to trap any exceptions.


WARNING!

POP3 connections are often open through a series of command and response exchanges. Some servers will close the connection to your program if they reach some arbitrary time-out period. To counter this, LPOP3Connection also inherits from LPeriodical. When the SpendTime() member function reaches a designated delay period, it tickles the server by sending a NOOP POP3 command. If you use the Internet classes outside of the normal PowerPlant framework, you will have to account for this functionality by periodically calling the SpendTime() function yourself.



LHTTPConnection

LHTTPConnection implements the Hierarchical Text Transfer Protocol (HTTP) for connections to software such as Web server programs. HTTP is a stateless protocol, it requests and potentially receives its data in a single transaction with the remote computer. The connection is opened and closed between each transaction. Usually the remote system does not maintain information about your program between these transactions (hence, the statelessness).

HTTP offers a variety of commands, called "methods" in the HTTP specification. LHTTPConnection supports three of the more popular commands: GET for retrieving a resource, HEAD for retrieving information about a resource, and POST for sending information.

Important LHTTPConnection functions:

 

Function
Purpose
LHTTPConnection()  
constructor  
Connection Management  
Connect()  
defaults to port 80  
Protocol Commands  
RequestResource()  
one transaction wrapper for sending an HTTP command and URL specified resource, defaults to a GET on port 80  
Get()  
one transaction wrapper for a GET on the URL specified resource, defaults to port 80  
Head()  
one transaction wrapper for a HEAD on the URL specified resource, defaults to port 80  
Post()  
one transaction wrapper for a POST on the URL specified resource, defaults to port 80  
Protocol Data Accessors  
SetCheckContentLength()  
set true (default) to have LHTTPConnection verify that the data returned in the LHTTPMessage is the same length as the Content-Length header field indicates  
GetCheckContentLength()  
returns true if content length checking is enabled  

In most cases, you will want to allow the different functions that implement the protocol commands (e.g. RequestResource(), etc.) to handle the opening and closing of the connection. It is relatively rare that you will need to use the Connect() and Disconnect() member functions.

HTTP defaults to TCP port 80, and if you do not specify otherwise, LHTTPConnection will use the standard port number. LHTTPConnection implements HTTP version 1.0.


NOTE

Uniform Resource Locators (URLs) are a way by which any item on the Internet can be specified and found. Think of URLs as your complete home address, by giving someone your URL they can locate and go directly to your resource. See RFC1738 for a detailed explanation of the URL format and how they can be used.



LFTPConnection

LFTPConnection implements the File Transfer Protocol (FTP). FTP offers authenticated access to a remote file system and it permits a variety of file and directory manipulation operations. FTP is most frequently used to send and retrieve files between computers.

FTP is a full featured protocol containing many different commands to manipulate file system objects. FTP was designed to abstract away the differences between file systems on different operating systems. When implementing an FTP client, you may want to have detailed control over the FTP session. Other times you may want to simply retrieve or send a single file. LFTPConnection implements easy to use wrapper functions for the simplest of cases while also providing a rich set of functions for detailed manipulation of the protocol.

LFTPConnection multiply inherits from both LInternetProtocol and LPeriodical.

Important LFTPConnection functions:

 

Function
Purpose
LFTPConnection()  
constructor  
Connection Management  
Connect()  
defaults to port 21  
SpendTime()  
periodically calls NoopServer() to maintain connection  
Protocol Commands  
PutFile()  
wrapper function for connecting, authenticating, and sending one file to a remote computer, defaults to port 21  
GetFile()  
wrapper function for connecting, authenticating, and retrieving one file from a remote computer, defaults to port 21  
RenameRemoteFile()  
convenience function for renaming remote files  
ListFolder()  
retrieves an LDynamicBuffer containing the full or name-only directory listing of the target directory  
SendRETR()  
sends a RETR command to get a file from remote computer  
SendPASV()  
sends a PASV command to specify a non-default port for the remote computer to listen to for data connections, default is for remote computer to initiate data connection  
SendSTOR()  
sends a STOR command to send a file to remote computer  
SendPORT()  
sends a PORT command to specify non-default client address and port to use by data connection  
SendTYPE()  
sends a TYPE command to specify the representation of the data to be transmitted, default is ASCII  
SendChangeDir()  
sends a CWD command to set a new working directory on the remote computer  
SendChangeDirUp()  
sends a CDUP command to set the working directory to the parent of the current working directory  
SendGetWorkingDir()  
sends a PWD command to retrieve the current working directory (in an LFTPResponse object)  
SendDeleteRemoteDir()  
sends a RMD command to remove the named directory  
SendCreateRemoteDir()  
sends a MKD command to make a specified directory  
SendSystemRequest()  
sends a SYST command to retrieve the type of the remote operating system (in an LFTPResponse object)  
SendDelete()  
sends a DELE command to remove the named file  
SendRenameFileFrom()  
sends a RNFR command to specify a file to rename (must be immediately followed by a call to SendRenameFileTo())  
SendRenameFileTo()  
sends a RNTO command to specify a new file name for a previously identified file (must call SendRenameFileFrom() immediately before this function)  
NoopServer()  
sends a NOOP command to the remote computer  
SendQUIT()  
sends a QUIT command to remote computer  
SendLIST()  
sends either LIST or NLST to retrieve the directory listing of the current working directory  
Protocol Data Accessors  
GetLastResponse()  
returns a reference to an LFTPResponse used by the last command  

The protocol command functions GetFile() and PutFile() are wrapper functions that handle the opening and closing of a connection. If the connection is already open, they will not automatically close it. Likewise, if the connection is closed, the connection will be closed on completion of the function.

The lower level protocol command functions require that the connection be open and the user be authenticated. If this is not true, the functions will throw exceptions.

Unlike other protocols, FTP makes use of multiple connections between the client and server computers. A control connection is maintained throughout the lifetime of the FTP session and is used to send commands and receive their status responses. FTP uses TCP port 21 as the default command connection port for all commands unless you specify otherwise. A separate connection-called the data connection-is created when file system objects are transmitted to or from the client. Data connections use a separate TCP port for their connections.

LFTPConnection provides an abstraction of the entire FTP session. The LFTPConnection object maintains the command and response connection. An internal class, LFTPDataConnection, is used by LFTPConnection to manage the data portion of a command transparently.

LFTPConnection implements the basic subset of commands found in RFC959.


WARNING!

FTP connections are usually open through a series of command and response exchanges. Some servers will close the connection to your program if they reach some arbitrary time-out period. To counter this, LFTPConnection also inherits from LPeriodical. When the SpendTime() member function reaches a designated delay period, it tickles the server by sending a NOOP FTP command. If you use the Internet classes outside of the normal PowerPlant framework, you will have to account for this functionality by periodically calling the SpendTime() function yourself.



LInternetResponse

Internet protocols that follow the command and response model tend to have a similar scheme for formatting their response data. These responses are usually ASCII strings which start with a code (often a numeric code), followed by a separator (a space), then optional text that is often used to supply human readable equivalents to the initial code. Most protocols terminate the response with a standard delimiter, usually a carriage-return and line-feed (CRLF).

LInternetResponse is a simple class that encapsulates the response concept.

Important LInternetResponse functions:

 

Function
Purpose
LInternetResponse()  
constructor  
Response Accessors  
ResetResponse()  
clears out the internal storage of the object  
SetResponse()  
parses ASCII response into the internal format, this is a virtual member function  
GetResponse()  
returns an LDynamicBuffer with the text portion of the response  
GetResponseCode()  
returns the numeric code portion of the response  

LInternetResponse is an abstract class. The Internet classes will automatically create the proper response object for the protocol you use. There are subclasses of LInternetResponse for each protocol implemented in PowerPlant.

The specific LInternetResponse subclasses are:


NOTE

The Internet classes rely on the standard C++ exception mechanism to report errors and unexpected events during operation. When a problem occurs, the classes will usually throw an LInternetResponse derived object. You should be familiar with how to use the C++ exception mechanism when using the Internet classes. Remember that some protocols may signal a problem that has to do with conditions of the transaction, and that you will want to check the response codes to determine if your code can work around the situation (such as remote computer being busy).



LSMTPResponse

SMTP responses use the same format as the one described in LInternetResponse. SMTP uses numeric response codes with optional text to relay the state of the transaction.

Important LSMTPResponse functions:

 

Function
Purpose
LSMTPResponse()  
constructor  
Response Accessors  
SetResponse()  
parses ASCII response into SMTP response components  


LPOP3Response

POP3 responses do not use a numeric status code, but rather a simple success and failure indicator. Some POP3 commands are requests for additional information. The protocol embeds the resulting information in the response following the optional text and the CRLF delimiter.

Important LPOP3Response functions:

 

Function
Purpose
LPOP3Response()  
constructor  
Response Accessors  
SetResponse()  
parses ASCII response into POP3 response components  
GetStatus()  
returns the success code cast to a Boolean type
GetResponseData()  
returns an LDynamicBuffer containing the response information (if any)  


LHTTPResponse

HTTP uses numeric codes and optional text to indicate success or failure. HTTP responses are used differently than mail (SMTP and POP3) responses. In most cases, HTTP transactions are composed of a single command and response cycle. The resulting response contains the requested data (if any) or an error description which is frequently in Hierarchical Text Markup Language (HTML). LHTTPResponse builds an LHTTPMessage object to hold this data.

Important LHTTPResponse functions:

 

Function
Purpose
LHTTPResponse()  
constructor  
Response Accessors  
SetResponse()  
parses ASCII response into HTTP response components  
GetStatus()  
returns true if ASCII response contains an apparently valid response code
GetReturnMessage()  
returns an LHTTPMessage containing the response information (if any)  


WARNING!

Notice that the meaning of GetStatus() in LHTTPResponse and LPOP3Response is different. In the former, it is an indication that GetResponseCode() will return a supposedly valid code number. In the latter, it returns true if the response code indicates success.



LFTPResponse

FTP responses use a numeric code and optional text to indicate the success or failure of a command. Some FTP commands are requests for additional information. The protocol embeds the resulting information in the response within the optional text area.

Important LFTPResponse functions:

 

Function
Purpose
LFTPResponse()  
constructor  
Response Accessors  
SetResponse()  
parses ASCII response into FTP response components  
CommandOK()  
returns Boolean true value if response code equals FTP success code
GetResponseData()  
returns an LDynamicBuffer containing the response information (if any)  


LInternetMessage

Some Internet protocols encapsulate the data they transport inside of specially formatted messages (RFC822). A message is composed of two parts, a set of descriptive headers and a message body. Headers are composed of one or more field/value pairs. Individual protocols designate the desired order of fields in a header as well as which fields are expected and valid.

LInternetMessage is the base class that implements a storage object that models the RFC822 format. It has member functions that maintain a generic set of headers and a message body. When your program is ready to use the contents of the object, it builds a correctly formatted, complete message on demand.

Important LInternetMessage functions:

 

Function
Purpose
LInternetMessage()  
constructor, can start from scratch or take a buffer of a previously received message  
Message Accessors  
ResetMembers()  
clears out message components  
SetMessage()  
parses the supplied buffer into header and body components
GetMessage()  
builds and returns an LDynamicBuffer to a complete message  
SetHeader()  
parses the supplied buffer and store header fields  
GetHeader()  
returns LDynamicBuffer of the combined header fields
SetMessageBody()  
stores a copy of the supplied body buffer  
GetMessageBody()  
returns LDynamicBuffer of the body  
SetArbitraryField()  
adds or changes a header field  
GetArbitraryField()  
gets a named header field if it exists  

There are two subclasses of LInternetMessage:


LMailMessage

LMailMessage adds support for electronic mail oriented header fields. LMailMessage also provides basic MIME 1.0 functionality to support standard and multipart message bodies.

Most of the member functions manipulate specific mail header fields:

Some Important LMailMessage functions:

 

Function
Purpose
LMailMessage()  
constructor  
Message Accessors  
SetTo()  
stores list of To: addresses  
AddTo()  
appends to existing To: addresses
GetTo()  
returns LList of To: addresses  
SetCC()  
stores list of CC: addresses  
AddCC  
appends to existing CC: addresses
GetCC()  
returns LList of CC: addresses  
SetDateTime()  
stores the message's date and time in internal format  
GetDateTime()  
returns a pointer to the internal DateTimeRec buffer  
SetFrom()  
stores a copy of the From: string  
GetFrom()  
returns a pointer to the From: string  
SetSubject()  
stores a copy of the Subject: string
GetSubject()  
returns a pointer to the Subject: string  
SetMessageBody()  
stores a copy of the supplied body buffer, handles multipart/mixed contents  
AddMessageBodySegment()  
appends an LMailMessage to internal list of body segments  
GetMessageBodyList()  
returns an LMailMessageList containing all body parts  
MIME Management  
SetIsMIME()  
set true if the message uses MIME  
GetIsMIME()  
returns true if message includes MIME content  
SetBoundary()  
sets multipart boundary string  
GetBoundary()  
returns a pointer to boundary string  
SetContentType()  
sets MIME Content-Type field value  
GetContentType()  
return a pointer to content type string  

LMailMessage has accessor functions for other mail related header fields. Please see the PowerPlant source code for a complete list.


NOTE

LMailMessage will support the MIME type multipart/mixed if you supply multiple message bodies, otherwise it defaults to text/plain. If you want to use another MIME type, you will need to set the MIME content type yourself and handle the type's behaviors.



LHTTPMessage

LHTTPMessage implements support for HTTP 1.0 header fields. This class implements the partial support for MIME that is expected in standard HTTP exchanges. You will need to remember to supply the correct MIME content type when you construct an LHTTPMessage object from scratch. Set the user agent field if you want to notify the remote computer of what kind of client it is communicating with. LHTTPMessage implements the basic HTTP authentication mechanism for you.

LHTTPMessage provides many functions to manipulate HTTP headers:

Some Important LHTTPMessage functions:

 

Function
Purpose
LHTTPMessage()  
constructor  
Message Accessors  
SetServer()  
stores Server type string  
GetServer()  
returns a pointer to server type string  
SetUserAgent()  
stores User-Agent id string  
GetUserAgent()  
returns a pointer to User-Agent string  
SetModSince()  
sets If-Modified-Since conditional date buffer
GetModSince()  
returns a pointer to the DateTimeRec buffer storing the If-Modified-Since date  
SetLastMod()  
sets Last-Modified resource age buffer  
GetLastMod()  
returns a pointer to the DateTimeRec buffer storing the Last-Modified date  
SetAllow()  
sets Allow string (the HTTP methods allowed)  
GetAllow()  
returns a pointer to the allow string  
SetWWWAuth()  
sets WWW-Authentication basic realm  
GetWWWAuth()  
returns a pointer to the basic realm string  
SetUserName()  
sets user name string used for authentication  
GetUserName()  
returns a pointer to the user name string  
SetPassword()  
sets password string used for authentication  
GetPassword()  
returns a pointer to the password string  
MIME Management  
SetContentType()  
sets MIME Content-Type field value  
GetContentType()  
returns a pointer to the content type string  

LHTTPMessage has accessor functions for other HTTP related header fields. Please see the PowerPlant source code for a complete list.


TIP

HTTP is not really MIME compliant, but it uses some MIME fields to indicate how to handle message contents. You should be sure to set the content type value of LHTTPMessages you create. The default type of text/plain will probably not be the type you are usually sending.



Internet Class Utilities

You will encounter several utility classes while using any of the PowerPlant Internet classes. Two classes are particularly prevalent:


LDynamicBuffer

LDynamicBuffer encapsulates a generic resizable buffer that grows or shrinks as its content changes. Since it is often difficult to predict how much data will be returned when using a number of the different Internet protocols, this class provides a simple, efficient solution. Many of the functions that return arbitrary data in the Internet classes will return LDynamicBuffer objects.

Some Important LDynamicBuffer functions:

 

Function
Purpose
LDynamicBuffer()  
constructor  
SetBuffer()  
stores data in the buffer, replacing previous contents  
CatBuffer()  
appends to the current buffer  
ResetBuffer()  
clears out the buffer  
GetBufferSize()  
returns the buffer size in bytes  
GetBufferH()  
returns a Mac OS Handle to the internal data buffer  


LHeaderField

LHeaderField is a utility class that embodies the message header field concept described in "LInternetMessage." This class maintains the title of the field and its value, and builds a standard header string on demand.

Some Important LHeaderField functions:

 

Function
Purpose
LHeaderField()  
constructor  
SetField()  
parses and store the components of a complete header  
GetField()  
returns an LDynamicBuffer to a header built from the LHeaderField's title and body value  
SetTitle()  
stores the title string  
GetTitle()  
returns a pointer to the title string  
SetBody()  
stores the body's value  
GetBody()  
returns a pointer to the body value string  


Other Classes

LMailMessageList, LHeaderFieldList, and UInternet are utility classes that are generally used internally to the PowerPlant Internet class library. You may need to infrequently use their capabilities. Please see the PowerPlant source code to learn details about these classes.


Implementing an Internet Enabled Application

Adding support for an Internet protocol to your application requires a simple set of tasks when you use the PowerPlant library. The Internet classes abstract away many of the mundane details of Internet programming, allowing you to focus on the actual functionality you want to implement. Much as PowerPlant relieves you of having to worry about standard user-interface issues when you use the LPane hierarchy, the Internet classes implement the underlying network code and give you an easy interface to the Internet.

When it comes to working with Internet technologies, a vast number of options are open to you. This chapter focuses on the protocols currently implemented in PowerPlant. It shows you how to use of some of the features of the Internet classes to implement simple, frequently sought features. You can use these examples as a guide in your own work, and can pattern more complicated programming on the simple examples shown here.


NOTE

The "Internet Example" sample code and this chapter's exercise (MIST) on your CodeWarrior CD both include an implementation of a client that makes use of the protocols described in this chapter.


Many Internet protocols share the feature of one computer establishing a connection to another, and then issuing a number of commands. For each command, the receiving computer will usually send back a response. The communication between computers is often characterized as a client and server relationship (or sometimes called a consumer and producer relationship). The originating computer is the client, and its purpose is to either retrieve or send information to another program. The remote computer is often labeled the server machine. In actuality, a client machine can subsequently play the role of server, and vice-versa. Note also that it is possible for the two programs to be on the same machine, in which case, the relationship between the programs still remains the same.

Programs that send mail messages via SMTP or retrieve messages with POP3 are usually called mail clients (or user agents in mail protocol lingo). A program that gets Web pages via HTTP is a web client (or often a browser, depending on how it uses the information). An FTP client will connect to an FTP server to retrieve files to the client's computer or send files to the remote system. The PowerPlant Internet classes do not restrict you in the types of programs you can write. You can create clients, servers, or even both within the same program.

This section describes the steps you will take to create a typical client that uses an Internet protocol. The general procedure is the same regardless of the protocol you use. The following topics are included in this section:


Choosing a Protocol

Even before you can decide whether you are creating a client or server program, you need to understand which protocol is necessary to accomplish your desired task. If you know that you are communicating with a particular kind of server, then the choice may be trivial. If you are creating your own set of programs for both ends of a communication link, then you may need to better understand the features of the individual protocols to better match a protocol to your project. You may find that none of the protocols match your needs, and subsequently, you may need to create your own. You should note, however, that the protocols that currently exist in PowerPlant provide a rich set from which to start.

If you are dealing with electronic mail, then you will want to focus on the SMTP and POP protocol classes. You should examine the protocols to understand to what level of detail you need access. If you are sending simple messages, or want to have a simple way to check for waiting mail messages, you may be able to use the basic wrapper methods to get functionality up and running quickly. If you are creating a more complicated program--perhaps one that will act as a full featured mail agent--you will want to look at the advanced methods.

If you need to communicate with a web server, you will want to examine the HTTP classes. These classes give you access to the most common communication techniques for interacting with the servers in place today. HTTP is a simple protocol, and much of its flexibility derives from the fact that you can send pretty much any kind of message embedded within its data stream. If you need to retrieve resources from a web server, want to send feedback using an HTML Forms-like mechanism, or want to tap into other Common Gateway Interface (CGI) processing, this class will help you get started.

If you want to manipulate remote files at a more detailed level, then FTP may be the protocol you are looking for. You can retrieve remote files, send local files to the remote site, list, delete, and rename remote files, and do many other tasks required to manage a file system.


Creating a Protocol Client

Once you have decided which protocol you are going to use, you will need to build the surrounding infrastructure in your program to support the protocol classes. Generally you will want some kind of user interface that provides a way to manipulate the data that you will be interacting with on the server.

The client will be the originator of the communications link that you are creating, regardless of the protocol. The client will also be the code responsible for managing that connection. It constructs the local content that may need to be sent, properly formats the messages for transmission, gets the proper addressing information to contact the remote system, creates the communications thread, handles any errors that may occur, sends commands and data, receives responses and requested data, and cleanly closes the communications link when finished.


Preparing Content

You may choose to have your main client code create or gather the data necessary for transmission over the protocol you have chosen. The data may be text of an email message and its accompanying email addresses or it may be something as simple as responses to a dialog that you will send to an HTTP server for processing as an HTML form.

You can decide to create a fully formed message within your client code, or just collect the raw information. Minimally, you will need to know the addressing information of the remote system in order to establish the connection. Other data depends on your use of the protocol.

If you are using a protocol that will send some kind of data to the remote system, it is largely a matter of programming style and knowledge of your program's resource requirements as to whether your client just holds the raw data or creates an LInternetMessage (or derivative) based object to hold the data.


Addressing the Remote Computer

The protocols represented by the PowerPlant Internet classes are all well established Internet protocols, and as such, have assigned TCP/IP port numbers. The classes default to these standard port numbers. You will usually just need to provide an Internet address in DNS format when establishing your connection. (DNS names being in the form of "www.metrowerks.com".) The Internet classes require that the address be in the form of a pascal string (Str255).

If your situation requires that you connect to the remote host using a port number other than the standard number, you will also have to supply that information when you create the connection.


Creating the Protocol Thread

Internet class connections rely on the threaded network mechanism of the underlying network class hierarchy. You will need to create a thread to drive each connection that you open. Depending on the complexity of the communications task, creating a thread subclass is a matter of subclassing LThread, and creating a Run() function that implements your task. Listing 5.1 illustrates a simple function used to request a resource via HTTP.

Once the thread is instantiated, it will handle all communications duties. You can pass a client object pointer to the thread for easier access to data stored within the client. The client object is frequently where raw data is stored until an LInternetMessage based object needs to be constructed.

Threads are usually responsible for deleting themselves once their task is complete and this model is followed when using the Internet classes. You can fire and forget the thread from your client code. If you require more interaction with the thread during a session, you will want to establish some kind of signaling mechanism between the client and the thread. See the chapter on using the PowerPlant Thread classes for more information on how to program with threads.

If you are using a protocol to send data, such as an email message, you will want to build a properly formatted message before you start the connection. Depending on whether your client already created the message, or has been holding raw data collected from the program's user interface, the start of the thread is a good time to construct the LInternetMessage based object.

Simple HTTP Thread Run() Method:


void *
CHTTPSendMsgThread::Run()
{
   try {
      LHTTPResponse theResponse;
   // connection will report progress to the thread
   // (this thread is an LListener)
      LHTTPConnection connection(*this);
      connection.AddListener(this);

   // constructs the message from raw data stored elsewhere
      LHTTPMessage theMessage;
      BuildMessage(theMessage);

      connection.Post("\pecho.metrowerks.com",
                      "\p/cgi/register.cgi",
                      theMessage,
                      theResponse);
      connection.RemoveListener(this);
   // connection is cleaned up as we leave try scope
  }
   catch (...) {
   // errors and problems from the Post wrapper should be
   // handled here if possible
   }

return nil;
}


Creating a Connection

The PowerPlant Internet classes provide a number of different ways to interact with the protocols they model. Frequently you will want to accomplish a very simple task, such as sending a single mail message, or retrieving one picture from a web server. Other times you will need to manage each command as it is sent to the remote computer, and work with each response given. To facilitate this kind of need, the classes provide both simple, "one-shot" methods, that wrap up all of the steps required to complete a task in that protocol into one function call. In some of the classes-POP and FTP in particular-you can work at a finer level of detail, and drive the session by sending individual or small sets of commands.

When you are working with the complete transaction wrappers, such as LSMTPConnection::SendOneMessage() or LHTTPConnection::Get(), a connection will be opened for you and closed after all of the task's intermediate steps have completed. When you use these commands, you do not need to worry about the state of the connection, but rather you can think on the higher level of your task.

On the other hand, all of the protocols provide the means for you to open a connection to a remote computer using the classes' Connect() functions. When you use this mechanism, you have a finer level of control over whether the connection stays open after a transaction completes-you can keep it open for subsequent usage. When you open a connection manually, you supply a computer's DNS address in the form of a Str255 (e.g. "\pwww.metrowerks.com") and can supply an optional port number. If you omit a port number, the default port number for the protocol is used.

Regardless of whether you then use the "one-shot" wrapper methods or the more detailed functions, the link will stay open for your use. This may be desirable for performance or other reasons.


NOTE

If you want to use some of the more advanced connection methods within a protocol-such as the individual commands within POP3 or FTP-you will have to open the connection for yourself.



Sending Content to a Server

Whether you manually opened a connection or are relying on the automatic mechanism, sending content to the remote computer is a simple matter of properly formatting the data within the appropriate LInternetMessage derived object (if applicable), and passing it to one of the messaging functions.

Depending on the protocol, you will need to supply different pieces of data when you build the message. The LInternetMessage class accumulates the data you provide as you supply it within different header fields and the message body itself. The class knows how to assemble this data into a properly formatted data buffer for transmission via the selected protocol. You can concentrate on supplying the basic information and the class will do the rest.


Receiving Responses From a Server

The protocols implemented with the PowerPlant Internet classes follow the command and response model of communication. Responses are issued by the remote computer after receiving-and possibly acting upon-a command or piece of data from the local computer. Of course, it is possible for this arrangement to be reversed, think of the response as the acknowledgment given by the receiving computer, whichever it may be.

Responses are generally of the form of some code which represents the success or failure of the action, followed by additional data, possibly including some form of embedded message. Responses in this class library are derived from the base class LInternetResponse.

The protocol wrappers shield you from much of the details of the protocol's transactions, but it is a good idea to understand the general meaning of the responses that your client can receive. You should look at the appropriate RFCs for a listing of possible responses. In most cases, the connection classes will translate the individual protocol's response codes into the generic message codes used when broadcasting progress messages to your client.

In protocols such as HTTP, where the transaction is only composed of a single command, the response will include the requested resource or some other server generated message-often in HTML-that is supplied in the form of an LHTTPMessage. In POP3, the response when using the GetOneMessage() includes an LMailMessage object. Some protocols' responses are simple error codes that indicate the state of the server and the results of the command.


Listening For Progress Messages

Some function calls result in a series of commands being issued to the remote computer, or perhaps transfer large quantities of data. In these cases, the connection object will issue progress messages at each stage of the transaction. With long data transfers, some of the protocols will periodically notify you of the status of the transfer. Your use of these progress messages is optional, but they can help you keep your client abreast of the connection's state.

The progress mechanism broadcasts a generic message (see Table 5.16) and includes a pointer to the progress object. The progress structure (see Listing 5.2) includes counts of the number items (mail messages, files, etc.) that it is operating upon, and (where appropriate) how many bytes are involved with the transmission.

Generic Protocol Progress Messages:

 

Message Constant
Generic Meaning
msg_OpeningConnection  
Connect() about to be called  
msg_Connected  
Connect() succeeded  
msg_Disconnected  
Disconnect() succeeded  
msg_SendingData  
Sending data in progress  
msg_ReceivingData  
Receiving data in progress  
msg_SendItemSuccess  
Successfully sent one item  
msg_SendItemFailed  
Failed sending one item  
msg_RetrieveItemSuccess  
Successfully received one item  
msg_RetrieveItemFailed  
Failed receiving one item  
msg_DeleteItemSuccess  
Successfully completed a delete command  
msg_DeleteItemFailed  
Failed completing a delete command  
msg_SendingItem  
Starting to send an item  
msg_ReceivingItem  
Starting to receive an item  
msg_ClosingConnection  
Disconnect() about to be called  

You should note that the message transmitted by the BroadcastProgress() function is a standard code that is used in all protocols to indicate what the Internet class library is currently doing. The actual meaning of the codes are somewhat context sensitive, some make more sense in certain protocols than in others. The code does not necessarily reflect the protocol specific state or response code of the active protocol. For that, you should refer to any LInternetResponse derived objects you may receive either directly via the various function calls or indirectly by the exception mechanism.

The Progress Structure:


struct SProgressMessage {
   LInternetProtocol *theProtocol;// src protocol object
   LStr255   currentItem;         // descriptive text for item
                                  //   currently being manipulated
   UInt32    totalItems;          // total items involved 
                                  //   in transaction
   UInt32    completedItems;      // completed count in items
   UInt32    totalBytes;          // total bytes in transaction
   UInt32    completedBytes;      // completed count in bytes
};

To receive progress messages, you need to attach an LListener to the LInternetProtocol you want to monitor. You will usually do this when you create the protocol object. See Listing 5.1 for an example.


Closing Down a Connection

If you are using the simple wrapper functions for the LInternetProtocol object in your program, and if you haven't manually opened the connection, the protocol object will handle the disconnection and cleanup of your communication link for you.

If you have manually opened the connection with Connect(), the wrapper functions will not close down the connection. Use Disconnect() to accomplish this task.

You should be sure to capture any exceptions during the use of both the simple wrapper functions and the more detailed protocol functions. Most of the communication-oriented functions do not close the connection on an exception, so you will need to do that yourself.

If you just destroy the LInternetProtocol object, its LEndpoint object will be destroyed, but the proper protocol rundown procedure does not occur. The correct closing sequence for each protocol is implemented in its Disconnect() member function.


Handling Abnormal Conditions

When a problem occurs during the operation of a protocol, such as an error message being returned from the remote computer, the LInternetProtocol object will throw an appropriate LInternetResponse based object. You should usually get into the habit of surrounding your networking code with try and catch blocks to capture these exceptions. Many times, you may be able to correct the problem, or at least notify your user of the problems existence, and then carry on with the operation.

The Internet classes are built on top of the PowerPlant network classes and this leads to another source of possible exception codes. The network classes will throw exceptions when they encounter errors in the operating system networking code. In most cases, these exceptions will be propagated up through the Internet classes. You should be prepared to catch and handle these exceptions in your code.

Serious errors coming from programming mistakes within your client code will also frequently cause exceptions to be thrown. When a protocol detects that it is in an illegal state for the operation you are attempting, it will throw an exception based on the boolean result comparing the current state with the expected state. One example of this is when you forget to open a connection (or the connection doesn't open properly) and you proceed to try to use a function that sends data.


TIP

You may want to have separate catch blocks for the different kinds of exceptions thrown by the Internet classes. The first could catch LInternetResponse objects, the second could check for exceptions such as PowerPlant network class error codes or false assertions, and a third should catch all other exceptions.



Summary of Internet Protocol Usage in PowerPlant

Adding Internet awareness to your programs is becoming more and more important each day. Whether you want to be able to register your user over the Internet by taking advantage of your Web site, or you want the user to send technical support questions via electronic mail, there are an unlimited number of capabilities you can add to your application by taking advantage of just a few standard Internet protocols.

The PowerPlant Internet classes provide implementations of the most frequently used protocols on the Internet today. By giving you access to HTTP, SMTP, POP3, and FTP, you can concentrate on inventing new features for your program that take advantage of this foundation, and you can avoid the drudgery of constantly reinventing the wheel.


Code Exercise

The Mini Internet Support Tool program (MIST) illustrates how to build selective Internet protocol functionality into your application to add common support features. It shows one use of each of the main protocols provided by the PowerPlant Internet class library. Although there are many different ways to use each protocol, this example should give you a basic understanding of the classes, and how simple it is to add Internet capabilities.

The purpose of this exercise is to give you experience using the Internet classes in PowerPlant. You will learn about some of the more common member functions and how to format, send, and receive Internet messages. This exercise does not delve into the details of the individual Internet protocols, nor is it a tutorial on network programming in general. You should examine the topic "Where to Learn More About Internet Protocols" for that kind of information.

In this exercise, you will create portions of the Mini Internet Support Tool program. As you gain experience with the Internet classes, you will notice that many of the steps to add a protocol into your program are similar for each of the other protocols.

Before we begin the exercise, there are some issues you should note. This code is structured in a simple manner to make it easier to understand the steps needed to add Internet functionality into your application. The code avoids heavy error checking and does not capture all of the possible return results from the remote computer. This exercise also makes use of the precompiled header feature of PowerPlant, so you will notice that header files for non-Internet classes are not included in most files.

Let's look at the steps you will take to add simple Internet functionality. In this exercise you will write code to:

SendRegistrationMessage() CRegisterViaHTTP.cp

The protocol code for each of the Internet classes expects to run from within the body of an LThread derived object. You must subclass a thread object and override its Run() method to make your calls to the remote computer. You will usually instantiate the thread object from within your client code and use LThread::Resume() to get it started.

As usual, the existing code is in italic.


   mThread = nil;
   mThread = new CRegisterViaHTTPThread(this);
   if (mThread)
      mThread->Resume();

2. Build an HTTP message.

BuildMessage() CRegisterViaHTTP.cp

In the HTTP protocol, data is exchanged between computers using LHTTPMessages to package the information into the format specified in the protocol's RFC. When you create an empty LHTTPMessage object, you need to populate the minimum header fields for the operation you are trying to complete.

MIST collects information from the user to send to an HTTP server to complete an on-line registration form. The MIST program mimics the operation of a Web browser's form capabilities by using an HTTP POST command to send data that has been specially formatted using an HTML form encoding.

After setting the body data you need to set the content type of the data, and to be helpful to the Web server, the type of client program sending the data.


theMessage.SetMessageBody(*theFormH,theLength);
theMessage.SetUserAgent("MIST");
theMessage.SetContentType("application/x-www-form-urlencoded");

The LHTTPMessage automatically sets other headers when you supply body data to correctly identify the length of the message.

3. Post HTTP data to a web server.

Run() CRegisterViaHTTP.cp

Your thread is now running and has some data to transmit to the Web server. You need to create the protocol object, and tell it to send the data using the wrapper function LHTTPConnection::Post().


LStr255 theHost(STRx_HTTP, str_HOST);
LStr255 theResource(STRx_HTTP, str_URL);
LHTTPResponse theResponse;
LHTTPConnection connection(*this);
connection.AddListener(this);
connection.Post(  theHost,
                  theResource,
                  theMessage,
                  theResponse);

4. Check the response code.

DisplayResponse() CRegisterViaHTTP.cp

When the POST command completes, it returns a status value from the remote computer in the LHTTPResponse object. You should check the return value to determine the success or failure of the POST command. An HTTP transaction is composed of one command and response cycle. If you receive a status code that indicates an error, you will need to reissue the command after possibly correcting the message contents, host, or resource specifier.


SInt32 theResponseCode;
theResponseCode = theResponse->GetResponseCode();
if (kHTTPRequestOK == theResponseCode ||
    kHTTPRequestNoResponse == theResponseCode)
   mProgress->SetDescriptor(
      LStr255("Registration transmission was a success"));
else
   mProgress->SetDescriptor(LStr255("Failure"));

5. Create a thread to run SMTP.

SendRegistrationMessage() CSendQuestionSMTP.cp

Like the other protocol objects in the Internet class library, you need to create an LThread based object to run the SMTP transaction. Once the client code has gathered up all of the desired data, create your thread, and start it running by calling its Resume() function.


mThread = nil;
mThread = new CSendQuestionSMTPThread(this);
if (mThread)
   mThread->Resume();

6. Build a mail message.

BuildMessage() CSendQuestionSMTP.cp

Electronic mail messages are modeled by LMailMessage objects. Like the LHTTPMessage class, LMailMessage adds support for setting the most frequently used header fields geared towards email. LSMTPConnection sends LMailMessages to the destination addresses you provide. Minimally, you need to specify a To and From address to send a mail message. It is helpful to add a Subject to the message as it both helps the recipient know what the mail message is about, and the Subject string is used by LSMTPConnection's progress mechanism to notify you of which message it is sending. In this exercise, you need to add a special header field "X-Mailer" so that you can tag the message with the type of email client that was used to send the message. You can use the LInternetMessage::SetArbitraryField() function to add any field that doesn't have its own specific access function.


ThrowIfNot_(mExample->GetEmail(anEmailAddr));
p2cstr(anEmailAddr);
theMessage.AddTo((char *) anEmailAddr);
theMessage.SetFrom((char *) anEmailAddr);
theMessage.SetSubject("MIST: Tech Support Question");
theMessage.SetArbitraryField("X-Mailer", "MIST");
ThrowIfNot_(mExample->GetQuestion(aQuestionH));
UInt32 theQuestionSize = ::GetHandleSize(aQuestionH);
StHandleLocker theLock(aQuestionH);
theMessage.SetMessageBody(*aQuestionH, theQuestionSize);

7. Send a mail message with an SMTP wrapper function.

Run() CSendQuestionSMTP.cp

The bulk of the code to implement a protocol's transaction is frequently located in the thread's Run() function. Once you have constructed your LMailMessage and decided on its destination, you can make use of the LSMTPConnection::SendOneMessage() wrapper function. By using the simpler API of the wrapper functions, you avoid all of the complicated details of running the protocol.


LSMTPConnection connection(*this);
connection.AddListener(this);
connection.SendOneMessage( theHost, theMessage);
connection.RemoveListener(this);

8. Capture an exception generated by the connection.

Run() CSendQuestionSMTP.cp

The LInternetProtocol derived classes report status and error information using two principal methods. They will throw an exception when an unexpected event or error occurs and they can report general status information through the progress mechanism.

You should be sure to place try and catch blocks around your protocol function calls to handle the exceptions generated by them.


catch (ExceptionCode err) {
   SysBeep(30);
   if (err_AssertFailed == err)
      DisplayProgress("Message was not sent, no connection");
   else
      DisplayProgress("Connection failed due to unknown reason");
}

If you are using the progress mechanism, you will need to add the appropriate test for the progress message error codes in your thread's ListenToMessage() function. LSMTPConnection will report a msg_SendItemFailed status code if the LMailMessage can't be sent.


switch (inStatusCode) {
   case msg_SendItemFailed:
      sprintf(statusMessage, "Failed to send: %#s", 
              theMsg->currentItem);
      DisplayProgress(statusMessage);
      SysBeep(30);
      break;
   default:
      break;
	}

9. Retrieve mail message headers via POP3.

Run() CCheckPOP.cp

You can make use of the various LInternetProtocol derived classes' wrapper functions to help you make decisions about more sophisticated processing. Suppose that you want to selectively handle email messages depending upon the kind of mail client that was used to send the message. You can retrieve mail headers without having to download the potentially bulky message bodies by using the LPOP3Connection::GetHeaders() function.


LMailMessageList theHeaderList;
POP3Connection connection(*this);
connection.AddListener(this);
connection.GetHeaders(
   theHost,
   theUsername,
   thePassword,
   &theHeaderList,
   mExample->GetUseAPOP());
connection.RemoveListener(this);

The GetHeaders() function returns an LMailMessageList of LMailMessage objects. These LMailMessage objects do not contain the body portion of the mail message.

10. Scan mail messages for arbitrary header fields.

ScanListForMIST() CCheckPOP.cp

Now you can scan through the list of LMailMessage headers looking for messages sent using the MIST client. A header field that describes the type of email client that sent a message is not always supplied. Furthermore, the RFCs which define the format of mail messages do not include a standardized header field that gives this kind of information. Therefore, you will look for an experimental field called "X-Mailer" which you always provide in any outgoing mail messages sent by the MIST client. You use the LInternetMessage::GetArbitraryField() function to find fields that are not supported directly by the Internet classes' access functions.


SInt32 msgCount = 0;
LHeaderField tmpField;
LMailMessage *currMsg;
LArrayIterator iter(theMsgList);
while(iter.Next(&currMsg)) 
{
   if (currMsg->GetArbitraryField("X-Mailer", &tmpField))
   {
      if (0 == strcmp("MIST", tmpField.GetBody()))
         ++msgCount;
   }
}

11. Retrieve a directory listing via FTP.

CLoadListFTPThread::Run() CRetrieveUpdateFTP.cp

Suppose you have released a series of update files for your user and you would like her to pick a file from a list that best meets her needs. You can cull such a list from the files stored on your FTP server. By using the LFTPConnection::ListFolder() function, you gather the names of all of the files in a directory, and can use that data to build a pick list in your user interface.


progress.currentItem = theHost;
connection.BroadcastProgress(msg_OpeningConnection, 
                             progress, true);
connection.Connect((ConstStr255Param) theHost);
connection.BroadcastProgress(msg_Connected, 
                             progress, true);
connection.ListFolder(&theListBuffer, p2cstr(theRemoteDir), true);

progress.currentItem = theHost;
connection.BroadcastProgress(msg_ClosingConnection, 
                             progress, true);
connection.Disconnect();
connection.BroadcastProgress(msg_Disconnected, 
                             progress, true);

Because ListFolder() is not a wrapper function, you will need to initiate the remote connection yourself. You might want to keep the connection open after this call in anticipation of the user selecting a file from the list and wanting to start a download. If you follow the leave-it-open strategy and later use one of the wrapper functions to download a file, you will have to remember to close the connection manually. The wrapper functions leave connections in the state they find them in. In this example, we are closing the connection so that later use of a wrapper function will reopen the link.


TIP

Notice the calls to BroadcastProgress() in the CLoadListFTPThread::Run() function. Wrapper functions contain calls to the progress mechanism to notify your code of the state of a connection. However, if you manually open and close a connection, and use various utility routines in-between, you will have to insert your own calls to the BroadcastProgress() function if you want your code to generate progress messages.


12. Download a remote file.

CRetrieveFTPThread::Run() CRetrieveUpdateFTP.cp

Now that a file has been picked for downloading, it is really easy to initiate a file retrieval operation using the wrapper function LFTPConnection::GetFile(). In this example, we are using the username "anonymous" with a password that is equivalent to our email address. This is the standard access information for a guest connection on many FTP servers.


connection.AddListener(this);
connection.GetFile( (ConstStr255Param) theHost,
                    "anonymous", "MIST@metrowerks.com", "",
                     FTPASCIIXfer, p2cstr(theRemoteFile),
                     &theSaveFile);
connection.RemoveListener(this);

13. Build and run the application.

After the application compiles and runs successfully, you will be able to make one of four choices in the Tools menu.

The Register command brings up the window shown in Figure 5.2. Enter your correct Internet mail address in the email field, and any other values for the rest of the form. When you press the Register button, the window's contents are packaged into an LHTTPMessage and transmitted to the remote computer (a Web server at Metrowerks, in this case). If you supplied a correct email address, a mail message will be sent to you containing a display of the values you supplied in the form.

Registration using HTTP:

To use the next two tools, first go to the Preferences command (found under the Edit menu). Enter your SMTP and POP3 DNS host names in the dialog and press OK. You will now be ready to run the rest of the exercise code.

You can choose the Contact menu item to send a simulated technical support question via SMTP. The window in Figure 5.3 requires that you enter your own email address and a question. (If you have set the appropriate server addresses in the Preferences dialog, the message you send will be echoed back to you by the mail server.) You could use a mail feature like this in one of your programs to automatically send questions to a well know email address (such as technical support) from within your application.

Technical Support Question via SMTP:

Next, if you select the Check menu item, you will be presented with a window as shown in Figure 5.4. Here you should enter the POP3 user name and password for your email account. If your POP server is appropriately specified in the Preferences dialog, the program will log on to your POP server and it will scan your mailbox for any messages that were sent to you from the MIST client. You can send one or two messages from either the Contact Tech Support window or the Register window to give the scanner something to look for. The code demonstrates a technique for selectively finding and operating upon specific mail messages waiting on a remote server.

Checking for MIST Mail via POP3:

Lastly, if you select the Retrieve Update menu item, you will see a window as shown in Figure 5.5. If MIST can connect to the remote FTP server, it displays a list of files in the target working directory. If you double-click on a file from the list and press the Retrieve button, MIST will download the file to your local hard drive. The code demonstrates a technique for finding and retrieving specific files on a remote server. You could use this technique in your own program to provide a way for the user to automatically get updates or enhancements to your application.

MIST is a simple collection of examples whose main purpose is to illustrate just how easy it is to use the Internet protocols as implemented in PowerPlant. With this new arsenal of tools, you should be communicating across the Internet in no time!

Downloading a file via FTP:

 

 

 


[ First ]  [ Previous ]  [ Next ]  [ Last ]  [ Manuals ]

Visit the Metrowerks website at: http://www.metrowerks.com
For assistance contact Metrowerks Technical Support at: cw_support@metrowerks.com
Copyright © 2000, Metrowerks Corp. All rights reserved.

Last updated: July 21, 2000