OS/2 eZine - http://www.os2ezine.com
Spacer
June 16, 2002
 
Douglas Clark is a program management consultant who first started using OS/2 version 1.3. He's married, with 2 girls, and is old enough to remember when 4 color mainframe terminals were a big thing.

If you have a comment about the content of this article, please feel free to vent in the OS/2 eZine discussion forums.

There is also a Printer Friendly version of this page.



Spacer
Previous Article
Home
Next Article


Do you have an OS/2 product or service you'd like to advertise?


Report on Writing OS/2 Plug-ins

or

WarpDoctor verses Netscape

The WarpDoctor project is a volunteer/open-source project to build a web site that is intended to be a clearing house for information about OS/2; primarily information about compatibility between OS/2 and hardware and OS/2 and various software, but the site will also contain reference information on OS/2 such as programming manuals and the like. The open-source part comes from the tools that are being built in order to make the web site work. Because of the type and format of information that will be stored in the site and the WarpDoctor team's desire to keep site maintenance to the absolute minimum, the team is building new software components to meet the goals. This article is a report about the experiences we had building a Netscape plug-in component: what the plug-in does, tips and advice on how to build and install the plug-in, and using plug-ins for site integration.

The article is in two parts. This month we cover the problems we are trying to solve, how to write a plug-in in C, and the background necessary to understand how a plug-in integrates with the web browser and server. Next month we will cover using Rexx with the plug-in, installing the plug-in, and the issues of using the plug-in on multiple operating systems and with different browsers.


The Problem

Two main requirements from the WarpDoctor project led to making the plug-in: absolute minimum maintenance effort to keep up the site, and public input of the site contents.

The absolute minimum maintenance and upkeep requirement drove us to using a database to store all site content. Every page of content on the site, plus all the menu/links structure needed to get to the pages - the things you click on to get to the pages - are all stored in the database. The advantage to us is that we can build structures to automatically build links to pages of new content and we can insure that no dead-end links ever appear in the site by using regular database facilities such as triggers and referential integrity constraints.

Public input of content means that we are depending on the OS/2 community to keep the site up to date. While the WarpDoctor team will be adding and revising the information stored in the site the bulk of the information will (hopefully) come from OS/2 users. When an OS/2 user discovers a way to install some hardware device successfully or a source for device drivers, the idea is that he would come to the site and enter that information.

This means that we needed some way for the general public to make input to our SQL database. Sometimes very large input. For example one of the topics we have on configuring Netscape is over 650K of HTML text. We also envision a wide array of content: HTML text, PDF, Postscript, and storage of device drivers and other software within the database. We need not only to provide a way of typing text into the database but also some way of uploading files and storing the content from the file into the database. After all, who wants to type 650K of text into a data entry screen, and you can't make a data entry screen for entering PDF data. What we needed was a data entry screen with an attach file button, where the "attached" file is uploaded to the server to be input into the database.

Uploading Files to a Web Server

There are three basic ways of uploading a file from a client to a web server.

The most straightforward way of uploading a file from a client machine to a server machine is having the user use the FTP feature of Netscape. The user types an FTP address in the address area of Netscape to connect to a FTP server, then uses the File - Upload File... menu option to select and send the file. Messy but it works. The problems with this method are: 1) it take more user intervention to get the file uploaded, 2) it is not integrated with the data entry process and 3) it is very difficult to associate the file that has been uploaded with the rest of the data entered on a data input screen.

The most integrated method is to use the <Input Type=File> HTML tag/parameter combination on an HTML form used for data entry. This tag places a text entry area on the form where a file name can be typed and also places a BROWSE button next to the text entry box. The BROWSE button opens a standard file dialog box where the user can pick the file he wishes to upload. When the form is submitted the browser sends (or is supposed to send) the contents of the file in a special format called multi-part MIME. You have to write a CGI program on the server side that intercepts the contents sent by the browser and save those contents to a file on the server's hard drive. This by far is the most desirable method because it is integrated with the data entry form, it doesn't require a FTP server to process the file, and it doesn't require any software on the client side other than the browser. Unfortunately it also doesn't work, at least with the OS/2 version of Netscape. I converted the Unix source from www.kessels.com/Upload/index.html to OS/2 in order to test Netscape under OS/2 uploading a file to an OS/2 web server. What I found was that when uploading binary files Netscape more often than not would not send the entire contents of the file. When it did send the entire contents of the file the contents that were sent were not exactly identical to the file on the client. Clearly not an acceptable solution. It did seem to work fairly well sending plain text files, but our needs were to be able to handle text and binary files. The OS/2 ported version of the CGI program is available if anyone is interested.

This leaves the third method: writing software that resides on the client machine to perform, or assist in, the file upload process. The method we chose was a Netscape plug-in. But before we can discuss how the plug-in works, or how to make a plug-in, we need to cover some very basic background on how web servers and web browsers work.

In these next sections we will very briefly discuss how the various pieces of web communications work. The section is a very high level overview intended to provide just enough background to discuss plug-ins.

HTTP

Web browsers and web servers communicate with each other by sending messages back and forth. Every time you click on a link on a web page a message is sent from the browser to the server. When the server receives the message from the browser it decodes the message, figures out what the message is requesting, and returns a message to the browser. The format of the messages is defined by a protocol called HTTP - Hyper Text Transfer Protocol. The HTTP protocol defines both the format of the messages, and how the server and browser response to different types of messages and malformed messages. Your main concern is understanding the basic format of the messages.

Each message in HTTP consists of one or more headers, and an optional body. All messages will have at least one header but a message may or may not have a body, depending on the message type.

Each header in the message is on its own line, the line being defined by a terminating carriage return and line feed pair. The header section is terminated by a blank line. If a body exists, it appears in the message after the header section, that is after the blank line terminating the header section. We will look at two message examples below.

This first message example was generated by typing the Uniform Resource Location (URL) http:// 192.168.32.100/xhome.html in the address field of the browser. The first line of the message identifies this as a GET message, a message requesting data from the server. The first line also identifies what is being requested, i.e. the file xhome.html, along with the version of the HTTP protocol the message is formatted in. Other types of messages are: OPTIONS, HEAD, POST, PUT, DELETE and TRACE; the ones we are interested in are GET and POST - both of which request information.

The Connection: header requests that the socket be kept open for subsequent messages from the browser. The User-Agent header identifies the type of browser that is making the request. The Host line identifies the host portion of the URL that created the request, meaning the host that the message has been sent to. The Accept... headers define the type of content the browser can read (gif, xbitmap, jpeg, etc.), the types of encoding that can be applied to the body of the message, which languages the browser would like the text returned in, and the character sets or code pages the browser would prefer.

GET /xhome.html HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.61 [en] (OS/2)
Host: 192.168.32.102
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/ png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8

This first example message has no body because it is requesting information from the server. Most of the messages from the browser do not have a body. On the other hand most of the messages from the server do have a body because the server is usually returning information in response to a request and the information is in the body of the message.

The second message example was sent from a browser when the submit button on the following form was pressed.

This message is a POST type message. It is requesting the server to return information from the program RunThis.exe located in the server's /cgi-bin directory. This message, in addition to requesting information from the server, is also sending some data to the server to be passed along to RunThis.exe. That information is contained in the body of the message and comes from the two text input areas of the HTML form being displayed on the screen above. The body of the message being action=one&message=two. The header section has two additional header lines: Content-type, and Content-length. The Content-type header identifies the type of data contained in the body of the message. The content type is also called the mime type. The Content-length specifies how many bytes of data are contained in the body of the message. Notice the blank line between the header section and the body section.


POST /cgi-bin/RunThis.exe HTTP/1.0
Referer: http://192.168.32.100/testa.html
Connection: Keep-Alive
User-Agent: Mozilla/4.61 [en] (OS/2; U)
Host: 192.168.32.102:58682
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Content-type: application/x-www-form-urlencoded
Content-length: 22

action=one&message=two

The differences between this message and the previous message are:

  • This is a POST message rather than a GET message.
  • The headers Content-type and Content-length appear in this message.
  • This message has a body. In this example the body of the message is just one line.

The Content-type header specifies what type of data appears in the body of the message. The Content-length header specifies how many byes are in the body of the message. Messages that have a body almost always have Content-type and Content-length headers.

HTML

Hiearchical Text Markup Language is the language used in the majority of all web documents you see in your browser. HTML pages are contained in HTTP messages that have a Content-type of text/html and HTML is contained in the body of the message.

HTML is a combination of a language that describes text, and a very basic language for building simple data entry screens, called forms. The HTML language is made up of tags. The tags identify types of text, such as paragraphs, level one headings, level 2 headings, numbered lists, etc. The browser reads the HTML tags and decides how to format each type of text based on the browsers current settings. HTML tags are enclosed in angled braces, like this <tag> where the tag name is in the angled brackets. In HTML some tags require a beginning and ending tag while other tags are self contained, i.e. there is no corresponding ending tag. For those tags that require an ending tag, the ending tag is also the same name as the beginning tag, except the name begins with a slash. For example

<center>This text is centered on the page</center>

show the CENTER tag, which requires an ending tag.

The following is an example of a very simple HTML file and what it looks like in Netscape.


<html>
<body>
<h1>Level one heading</h1>
<h3>Level three heading</h3>
<p>This is a paragraph of text. A paragraph of just two sentences
</body>
</html>



Simple data entry type screens can be built in HTML in what are called forms. A form is indicated on an HTML page with a form tag - which is one of the tag types that also requires an ending tag. Between the beginning and ending form tags can appear a number of HTML tags that represent various "controls" such as: radio buttons, check boxes, push buttons, text entry boxes, drop down and pick lists, etc. The form tag can take a number of parameters such as the ACTION parameter and the METHOD parameter. The ACTION parameter specifies what program the server should execute when the form is "submitted". The METHOD parameter specifics which method (GET or POST) is used when executing the program in the ACTION parameter; we discuss this further in the CGI section below.

The following is an example of a very simple form in HTML, and what it looks like in Netscape.


<html>
<body>
<h3>Simple Data Entry Form</h3>
<form action='/cgi-bin/runThis.exe' method='POST'>
Enter Text: <input type='text' size=10' name='text1'>
<br>
<input type='submit'>
</form>
</body>
</html>



When the form is submitted the browser sends either a GET or a POST message to the web server, depending on the METHOD parameter on the FORM tag. The format of the message was discussed in the HTTP section above.

Common Gateway Interface - CGI

Web servers can be "extended" with external programs using the Common Gateway Interface (CGI). When an HTML form is "submitted" (usually by the user clicking the submit button) the web server executes the external program specified in the ACTION parameter and passes the data from the tags/controls in the "form" to the external program. The CGI specification defines how the web server passes information to the external program and how the external program returns information to the web server. The external program can be written in any language that can handle the methods used by the web server to pass information to the external program.

The method used by the web server to pass information to the external program is determined by the METHOD parameter on the FORM tag. In GET method the web server passes the data from the form to the external program in an environment variable called QUERY_STRING. In the POST method the web server sends the data from the form to the external program using STDIN. In both cases the data from the form is represented by a name followed by an equal sign, followed by the value from the tag/control. For instance, the form in the above example would send the data as

text1=some data

The external program communicates with the web server and web browser by sending output to STDOUT. The web server intercepts the output from STDOUT from the external program and sends the output to the browser. So really the CGI program is communicating with the browser through the web server. Since the output generated by the CGI program goes more or less directly to the browser, the output must be in a format the browser understands. More specifically, the output must be in the format of an HTTP message the browser understands. I said the output goes "more or less directly" to the browser because the web server examines the output and adds headers to the message (the output) if necessary before it passes the message to the browser. (The most common header added to the message by the web server is the Content-length header.)

For example if our program runThis.exe consisted of the following little C program


main(int argc, char **argv)
{
printf("Content-type: text/html\n\n");
printf("<html><body>Response from program: hello!</body><html>");
}

the program would return the following output


Content-type: text/html

<html><body>Response from program: hello!</body><html>

(The web server would add the header line Content-length: 54 to the message, plus some other header lines that we aren't concerned about for this article.)

Extending Netscape

Netscape can be "extended" three different ways: with helper application, with Java applets, and with plug-ins. Netscape can also be controlled by external programs through DDE, but that really isn't extending Netscape since the external program doing the controlling is completely removed from Netscape.

Helper applications are external programs that reside on the client machine and are called by Netscape when it encounters a MIME type (Content-type header) it does not handle internally, or when Netscape downloads a file with an extension associated with the application. Netscape saves the MIME type data to a temporary file and then calls the helper application program passing the temporary file name on the command line. MIME types and file extensions are associate with helper applications in the Edit - Preferences menu option.

A Java applet is a Java program that is invoked by Netscape when it encounters an < applet> or <object> HTML tag. A parameter in the applet or object tag specifies the name of the Java program to be downloaded and run, along with the size of the frame on the HTML page that will contain the program's output. The Java applet resides only temporarily on the client machine - it is downloaded each time it is run. The applet cannot access the client hard drive without requesting permission from the user.

A plug-in is an external DLL that are loaded by Netscape when it encounters a MIME type associated with the plug-in. The MIME type data is passed to the plug-in either as a temporary file or as a stream of data, depending on the plug-in's preference. The plug-in declares which MIME type(s) it handles when it is written and compiled. When Netscape starts up it checks each plug-in located in the plug-ins directory for the MIME types it handles and builds an association list that it uses to invoke the correct plug-in for a particular MIME type. The plug-in handles the data however it wants: some plug-ins handle graphical type data and display that data in a Netscape window, other plug-ins handle audio data and send the data to the computers speakers.

plug-ins are also loaded by Netscape when it encounters an <embed> or <object> HTML tag with a name parameter that specifies a plug-in name in an HTML page.

plug-ins are more integrated with Netscape than helper applications are. Plug-ins are notified of keyboard and mouse events by Netscape and can draw in Netscape windows, thus appearing to draw directly in the HTML page. Helper applications on the other hand are external applications that execute as their own process and draw into their own window. Both helper applications and plug-ins can access the user's hard drive without requesting permission from the user.

plug-in Overview

A plug-in is a module that is dynamically loaded by Netscape. The plug-in can

  • draw into a Netscape window
  • receive keyboard and mouse events
  • draw into part of a Netscape window, or create its own window to draw in
  • post data to the a URL - meaning send data to a CGI program
  • send a file to a FTP server
  • get data from a URL to a Netscape window, to a file, or as a stream directly to the plug-in
  • get a file from an FTP server

Plug-ins fall into three categories:

  1. Window - where the plug-in draws into a Netscape window, or more specifically into a frame whose dimensions are defined in the EMBED tag.
  2. Windowless - where the plug-in draws into a window it creates itself, rather than a Netscape window.
  3. Faceless - where the plug-in doesn't draw anything in any window.

We will only be discussing faceless plug-ins in this article. However you will see that the categories become blurred next month when we start discussing using Rexx with plug-ins.

Netscape communicates with the plug-in by calling functions in the plug-in, called plug-in Methods. The plug-in communicates and requests services from Netscape by calling functions implemented in Netscape, called Netscape Methods. plug-in methods begin with NPP_, for example NPP_New(). Netscape methods begin NPN_, for example NPN_Write().

Unlike an application, the life cycle of a plug-in is completely controlled by the web page that calls it. The life cycle details are:

  • When Netscape encounters data of a MIME type registered for the plug-in, or when it encounters an embed tag that names the plug-in, Netscape dynamically loads the plug-in DLL into memory if it hasn't been already loaded.
  • Netscape calls the plug-in method NPP_Initalize() to signal the plug-in that it is being loaded. The plug-in initializes whatever structures and allocates whatever memory it needs when the DLL is loaded in this function.
  • Netscape creates a new instance of the plug-in and calls the plug-in method NPP_New(). While the DLL is only loaded once into memory, there may be multiple "instances" of the plug-in active at the same time. This is possible if there are multiple embed tags naming the same plug-in on a single page, or, more likely, if multiple Netscape windows are open that reference the same web page with the embed tag. The plug-in sets whatever values and initializes whatever structures are needed for an instance in the NPP_New() function.
  • The plug-in instance is deleted when the user leaves the page associated with that instance or closes that page's window. Netscape calls the plug-in method NPP_Destroy() to notify the plug-in that a instance is being deleted. The plug-in should free memory used by the instance and do whatever other clean-up needs to be done in that function.
  • When the last instance of a plug-in is destroyed the DLL is unloaded from memory. Before the DLL is unloaded Netscape calls the plug-in method NPP_Shutdown() to notify the plug-in that is being unloaded.

Between NPP_New() and NPP_Destroy() the plug-in, just like a GUI program, waits for some event to happen that triggers an action in the plug-in. For windowed plug-ins those events are keyboard and mouse events. For faceless plug-ins the events are the creation of a new stream of data, or the completion of a Netscape method called by the plug-in. In a faceless plug-in it is easiest to include the actions you want do in the NPP_New() function that gets called when the instance initializes. You are limited somewhat in what Netscape methods you can call before the initialization completes but for simple tasks you can get away with placing those tasks at the end NPP_New()

The following two tables summarize the functions the plug-in must provide that Netscape calls (Plug-in Methods), and the functions that Netscape provides that the plug-in can call (Netscape Methods.)
Table 1. Summary of Plug-in Methods Called by Netscape
Function Name Description
NPP_Destroy Called by Netscape when a plug-in instance is destroyed.

NPP_DestroyStream Called by Netscape to signal when the stream is about to be closed

NPP_GetJavaClass Returns the Java class associated with the plug-in
NPP_GetValue Allows Netscape to query the plug-in for information
NPP_HandleEvent

Netscape calls this to deliver event information for a window
NPP_Initialize

Called by Netscape when the plug-in DLL is loaded
NPP_New

Called by Netscape when the plug-in instance is created
NPP_NewStream Netscape calls this to notify the plug-in that a new stream is created. The plug-in sets a parameter to tell Netscape what to do with the stream: copy the stream to a temporary file or send the stream directly to the plug-in
NPP_Print Called by Netscape when the user wants to print.
NPP_SetValue Netscape calls this to set information about the plug-in
NPN_SetWindow

Tells the plug-in when a window is created, moved, sized or destroyed.
NPP_Shutdown

Called by Netscape immediately before the plug-in DLL is removed from memory
NPP_StreamAsFile

Called by Netscape to pass the name of the temporary file Netscape created when a stream is directed to a file.
NPP_URLNotify Netscape calls this to notify a plug-in when it completes a URL request, either a NPN_GetURLNotify() or a NPN_PostURLNotify(). Netscape is asynchronous, in that the Netscape functions that get a URL or post to a URL return immediately, and Netscape called NPP_URLNotify() to signal to the plug-in when the data is actually posted or the URL is actually gotten.
NPP_WriteReady

Called by Netscape when a stream is being consumed directly by the plug-in. Netscape calls this to find out much data to transfer to the plug-in with NPP_Write(); the plug-in returns the number of bytes it wants in the next NPP_Write() in a parameter.
NPP_Write

Called by Netscape to deliver the stream data to the plug-in. NPP_WriteReady() and NPP_Write() are called repeatedly by Netscape until all the data is sent from the stream.

Table 2. Netscape Methods called by the Plug-in
Function Name Description
NPN_DestroySteam Closes and deletes a stream
NPN_ForceRedraw Forces a paint message for windowless plug-in.
NPN_GetJavaEnv Returns a pointer to the Java execution environment. This is used to communicate with Java.
NPN_GetJavaPeer Returns the Java object associated with the plug-in. This is used to communicate with Java.
NPN_GetURL Instructs Netscape to get a URL and return the URL to: a stream, an open Netscape window, a new Netscape window.
NPN_GetURLNotify Same as NPN_GetURL except Netscape calls NPP_URLNotify() when the URL is gotten.
NPN_InvalidateRect Invalidates a specified drawing are prior to repainting or refreshing a windowless plug-in
NPN_InvalidateRegion Invalidates a specified region prior to repainting or refreshing a windowless plug-in
NPN_MemAlloc Allocates memory from the Netscape's memory store
NPN_MemFree Frees a block from Netscapes memory store.
NPN_NewStream Requests the creation of a new data stream produced by the plug-in and consumed by Netscape
NPN_PostURL This function is seriously crippled
NPN_PostURLNotify Posts data to a URL. Netscape calls NPP_URLNotify() when the data is posted.
NPN_Reloadplug-ins Causes Netscape to recognize any new DLLs placed in the plug-ins directory since Netscape started
NPN_RequestRead Requests a range of bytes from a seekable stream
NPN_SetValue Sets a plug-in as windowless.
NPN_Status Sets a message in the status area of the Netscape window associated with the plug-in instance
NPN_UserAgent Returns information about Netscape
NPN_Version Returns information about the version of Netscape and the version of the plug-in API
NPN_Write Called by the plug-in to push data to Netscape for streams created by the plug-in and consumed by Netscape.

Programming the plug-in

To make a plug-in you need:

  1. The Netscape Plug-in SDK for OS/2. However this SDK has an error in two of the files: NPAPI.H, and NPOS2.CPP.
  2. Corrected version of NPAPI.H and NPOS2.CPP.
  3. If you want to build the example WarpDoctor plug-in you also need the source package This package includes the corrected files from the OS/2 plug-in SDK.
  4. The Plug-in Guide document from Netscape which describes the plug-in API. If is available either in PDF or as zipped HTML files
  5. VisualAge C++ version 3.0. It is theoretically possible to build DLLs in version 4 that operate with version 3 DLLs and executables but I find it easier just to break out the version 3 compiler in situations like this.

The SDK contains a number of sample plug-ins that you can use as a starting point to build your own. The most basic example is called NPSHELL, which is a example that contains skeletal functions for each of the plug-in methods, the NPP_ functions that Netscape calls in the plug-in. To use NPSHELL you copy the sample files to a new directory and edit the NPSHELL.CPP file to add your code to the function shells as needed.

The example code I am going to show is from the WarpDoctor plug-in, which was made from the NPSHELL sample program.

WarpDoctor Plug-in

The WarpDoctor plug-in is a faceless plug-in that performs two unrelated functions:

  1. File upload capability. This is used in the WarpDoctor data entry screens in order to attach a file to data sent in screen, as discussed at the beginning of the article.
  2. Rexx execution environment for executing Rexx programs downloaded from the web server on the client machine. The Rexx execution feature will be discussed next week.

The source for the WarpDoctor plug-in contains the simplified screens that are shown here in order to make it easier to modify the plug-in for your own use.

What it Looks Like

To perform a file upload the user loads the plugin_fileupload.html file, as shown below, and enters the name of a file to be uploaded.


The file name can be typed into the entry field or the Browse button can be used to select the file. If the Browser button is used you probably will have to change the list of file types in the file dialog box in order to see all the files in a directory; Netscape assumes that you want to upload an HTML type file.

When theUpload button is pushed an second window is opened, shown below.


This second window is the one that loads the plug-in.

The plug-in sends the file specified in the first screen using FTP to an FTP server, then it invokes a CGI program on the web server, passing the name of the file to the CGI program. For our simplified example the CGI program does nothing but display the message "Cgi program would do something here" in the second window, as shown below.


On the WarpDoctor data entry screen a different CGI program is executed that takes the values input on the data entry screen and inserts those, along with the contents of the uploaded file, into a row of the database.

How it Works

Our first screen is a simple form with an <input type='file'> tag and a single button. The <input> tag produces on the form the text entry box and the Browse button. The source is shown below.


This file is a little unusual in that we do not submit the form that is displayed by the file. Instead the Upload button executes a little JavaScript function (lines 4 - 15) that opens another window (line 14) with the file plugin_fileupload2.html. Normally the <form> tag has an ACTION parameter that specifies the CGI program to be called when the form is submitted, but we don't want to submit this form. The reason is, we want the Browse button and file dialog box that Netscape provides with the <input type=file> tag but we don't want Netscape to send the file because we know that doesn't work - at least with binary files.

Lines 6-7 get the current date and time, which is used in line 14 to create a unique "name" for the new window that is opened. We need to create a unique name for the new window in order to allow this form to be submitted multiple times simultaneously, hopefully each time to upload a different file, without each execution stepping on each other.

The HTML file that is loaded in the second window executes a little JavaScript routine that gets the file name from the first window, and builds an <embed> tag using the file name as one of the embed parameters. The source for plugin_fileupload2.html is shown below.


Line 4 creates a JavaScript variable called flName. Line 5 sets the variable flName to the value of the form control/tag named uploadFileName on the first window, which is our <input type=file> tag, shown on line 26 of the previous figure (file plugin_fileupload.html.) Lines 13 - 34 output the embed tag (lines 22-32 are commented out), which loads the plug-in. We have to use JavaScript to create the embed tag and its parameters, instead of hard-coding it in the file, because we don't know the name of the file that is going to be uploaded until this file is executed. The way this file works is:

  • Netscape reads the file and executes the JavaScript lines between the <script> tag on line 12 and the ending </ script> tag on line 35.
  • Netscape then reads the output generated by the JavaScript routine to produce a page.
  • When Netscape reads the output it encounters the <embed ... > tag and loads the plug-in.

This is what the page looks like that is built by the JavaScript


<BASE HREF="http://192.168.32.100/">
<html>
<head>
<TITLE>Uploading C:\adobe\READOS2\help\reader.pdf</TITLE>
</HEAD>
<BODY bgcolor='white' link='black' vlink='black' alink='black'>
<BR>
<H3>Uploading the data file</H3>
<EMBED type='x-warpdoctor/upload' hidden='true' border=0 name='npwrpdoc' pluginAction=1 action=79 filename=C:\adobe\READOS2\help\reader.pdf afterCgi='http://192.168.32.100/cgi-bin/pluginCgi'>
</EMBED>
</BODY>
<HTML>

When a plug-in is loaded by the <embed> or <object> tags Netscape passes the names and values of each of the parameters in the embed tag to the plug-in instance when it starts the instance. Since HTML ignores tags, and parameters on tags, that it doesn't recognize this allows us to pass "arguments" to our plug-in when it is loaded. We do this by adding parameters to the embed tag for the arguments we want to pass. In plugin_fileupload2.html lines 14-17 are required to get the plug-in loaded. Lines 18-32 are "extra" parameters that we have added to control the behavior of the plug-in.

Line 14 specifies a MIME type for this plug-in. The MIME type is pretty useless in this case since the plug-in is also identified by name on line 17. Line 16 says that there is no frame in which our plug-in is going to draw, and line 15 says that the plug-in is hidden. These are the lines necessary to get the plug-in loaded.

Line 19 (and following) is a parameter we created in order to pass an argument to the plug-in. The uploadAction argument tells the plug-in how to handle the original file that is uploaded. A value of 1 says to upload a copy of the file, 2 means to delete the original file from the client hard drive after it has been uploaded. 1 is the default.

Line 20 is the name of the file that is to be uploaded. Line 21 is the URL of the CGI program to be executed after the file is finished uploading. After the file is uploaded the plug-in will either:

  • execute a CGI program, and pass all the embed parameters to the CGI program. It does this if the AFTERCGI parameter/argument is passed with a value to the plug-in
  • display a URL in the second window or in a new window. It does this if the AFTERURL parameter/argument is passed with a value to the plug-in. The file pluging_after.html is provided in the WarpDoctor plug-in source package as an example. This allows you to display your own message after the file is uploaded. Line 22, which is commented out, shows how to specify the AFTERURL parameter.
  • generate its own status message saying the file has been uploaded, if neither AFTERCGI or AFTERURL is present.

In our example we are executing the CGI program pluginCgi.exe after the file is uploaded. You can put any CGI program here you want, including a Rexx program if your web server supports executing Rexx via CGI. Line 19 is used to pass a parameter to the CGI program. This works because our plug-in ignores parameters it doesn't recognize, just as Netscape ignores parameters to the embed tag it doesn't recognize, which means you can use <embed> parameters to pass arguments to the CGI program that is executed after the file is uploaded. A summary of the parameters for the embed tag used by Netscape and the WarpDoctor plug-in is show in the table below; you can add any parameters you want for passing to the CGI program as long as the name doesn't conflict with what is shown in this table..

TABLE 3. Embed Parameters used by Netscape and the WarpDoctor Plug-in
Parameter Name

Used By

Description

afterCgi

plug-in

Specifies the name of a CGI program to execute after the file is uploaded

afterUrl

plug-in

Specifies the name of a URL to be displayed after the file is uploaded.

autoCloseWin

plug-in

Number of seconds to leave window open before closing window. 0 = never close window - make the user do it. When the plug-in generates its own messages or error messages, the window that the message is displayed in is automatically closed after the number of seconds specified in the autoCloseWin parameter.

border

Netscape

Specifies the line-type to use for the border. 0 = no border

CgiDebug

plug-in

Turns on debug messages for the CGI program supplied in the WarpDoctor source distribution pluginCgi.exe

debugPlugin

plug-in

If PmPrintf has been compiled in the plug-in, sends debug messages out to PmPrintf.

filename

plug-in

The name of the file that is to be uploaded

ftpUrl

plug-in

Specifies the URL of the FTP server to being used for uploading.

hidden

Netscape

Specifies whether the plug-in appear in the HTML page or not

name

Netscape

Specifies the name of the plug-in to be loaded

pluginAction

plug-in

Specifies what to do with the original of the file that is uploaded. 1 = leave original, 2 = delete original after upload

targetWindow

plug-in

Target for output messages -and the window the CGI output is displayed in, if AfterCgi is present. Valid values are _self = same window that loaded the plug-in, _blank = a blank new window, name = the name of a frame which must already be open

type

Netscape

Specifies the MIME type associated with this plug-in instant

In the WarpDoctor Plug-in source package is included the CGI program pluginCgi.exe. This is used in our example to produce a message showing that the CGI program has been executed. If you use the CgiDebug parameter then pluginCgi.exe will show all the parameter names and values passed to it when it starts up. PluginCgi.exe is also used by the WarpDoctor plug-in to display error and status messages when the plug-in is not able to create temporary files on the client workstation, so pluginCgi.exe should be installed in the cgi-bin directory of any web server you are going to use the plug-in from. PluginCgi.exe is mostly the shell of a CGI program that you can take and modify to create your own CGI program. The main function is shown below.


Line 19 of plugin_fileupload2.html sets the parameter ACTION=79 when the plug-in is loaded. The ACTION parameter is passed from the plug-in to the CGI program pluginCgi.exe, which on line 32 above causes the CGI program to output the message "CGI would do something here". Notice that lines 49-54 in the figure above show how to output from a CGI program in HTTP message format.

Some Example Plug-in Functions

This section will show some examples of plug-in code from both the WarpDoctor plug-in and from the NPSHELL sample supplied in the Netscape Plug-in SDK.

Each instance of a plug-in has a pointer that can be assigned to storage allocated for holding data that needs to be passed between the plug-in and Netscape methods. An example of a very simple structure that is passed to the functions, from NPSHELL, is shown below. You can add your own fields to the structure for storing data you need for your plug-in.


The figure below shows the plug-in method called by Netscape when the plug-in DLL is loaded. This is where you would add any code you need to run once at the beginning of the plug-in.


After executing NPP_Initialize, Netscape then calls NPP_New to create an instance of the plug-in. It is here where you initialize the structure fields to the correct values. To see how the structure is passed to the other functions look at the NPN_URLNotify example below.


This next example, from the WarpDoctor plug-in, shows how to post data to a URL, i.e. a CGI program.

This function is used in the WarpDoctor plug-in to output messages when the plug-in cannot create temporary files on the client's hard drive. The function sends the message to the CGI program in the variable MESSAGE, setting the variable ACTION to indicate what type of message it is. The CGI program, pluginCgi.exe shown in a previous figure, creates HTML output that contains the message which the web server sends back to the browser. This rather complicated method of displaying messages was done to avoid using any platform specific GUI code in the plug-in to make it easier to port to other platforms.


Line 138 defines the variable myData to hold the message, and initializes the variable with the Content-type header and the first part of the Content-length header. Lines 142-143 add the actual length to the Content-length header - the +20 is to account for the action=99&message= part of the body, plus the terminating CRLF characters.

Notice that what you are doing is building an HTTP message simulating what the browser sends a web server from a page that has the <form> tag on it.

The last parameter to NPN_PostURLNotify on line 158 is the integer 97 (cast as void*). This value is used to identify to ourselves which notification we are receiving when we are notified that the URL has been posted, see below.

Note - that while the Netscape Plug-in Guide document shows an example of posting data using NPN_PostURL() that function does not work. You must use the NPN_PostURLNotify(), even if you do want to be notified; just pass zero as the last parameter if you don't care about notification.

This last example, from NPSHELL, shows the NPP_URLNotify function called by Netscape when a NPN_PostURLNotify or NPN_GetURLNotify has completed.


The "tracking" information you supplied to the get or post function (example: 97 from the previous figure) is passed as the parameter notifyData to the function so the function can tell which execution it is being notified about.

Conclusion

The Plug-in API allows Netscape to be extended to handle all sorts of special data and special situations. The plug-in API is also more powerful than helper applications because the plug-in can communicate back to the web server and the network using Netscape provided functions. Plug-ins can work with CGI programs on the web server to provide very flexible and powerful services to the client.

The WarpDoctor plug-in, while intended to solve WarpDoctor's site problems, was also designed to be generic enough to be used by anyone having similar needs - the need to upload files from the client to the server and to invoke a program when the upload is complete.

With a basic knowledge of how web servers and browsers communicate, and armed with the plug-in documentation and SDK, it is fairly simple to build a plug-in, especially on the OS/2.

Next month we will get more OS/2 specific because we will be covering Rexx integration into the plug-in. We show how to download Rexx code from the server and execute it on the client, both plain old command-line Rexx and GUI Rexx packages built with DrDialog. In addition we show an interface between Rexx and the plug-in that allows the Rexx program to execute most of the functions in the plug-in, meaning that you can use Rexx with the WarpDoctor sample plug-in to do most of the stuff you would normally have to write your own plug-in in C to do. Stay tuned.

Previous Article
Home
Next Article

Copyright (C) 2002. All Rights Reserved.