Chapter 30

Developing Web-based Bulletin Boards


CONTENTS


This chapter begins Part VIII, "Advanced Applications: Web-based Bulletin Boards," with a discussion of Webbased bulletin boards. In this chapter, we learn how to design applications for building a Web-based, bulletin board environment. The application introduced in this chapter is the WebEmail bulletin board.

Other chapters in this part introduce applications, such as the application used to append comments gathered from a form to a log file, and display the file on the Web. A guest book application is implemented as a board on which guests make brief comments to be seen by future guests. A board used to implement a situation reporting/tracking system is yet another application discussed.

Several kinds of Web-based bulletin boards are discussed in the next few chapters. They are

These three areas of Web-based bulletin boards each have similar foundations. Our list of characteristics can be found in different concentrations among all the flavors of the Web-based bulletin boards.

The Bulletin Board Environment

The bulletin board environment is about displaying articles. Articles are arranged by the application and presented in different ways depending on the type of sort wanted. Some articles are sorted by the date they were posted; others are sorted alphabetically by subject or author.

This application uses CGI scripts to create four basic pages of the bulletin board environment. (You can increase the number of pages as needed.)

The article page itself

For example, the article index page is a list of all the articles available for the particular forum. A user can see each of the articles' summary information on one page: a line with the subject, author, and the date, sorted in some order specified by the toolbars on the page.

When you select an article from the article index, you go to the second required page: the article itself. Each article should be in a standard format. HTML builders are a good resource for getting templates on how to lay out each page.

The CGI script that does the automatic page generation is just throwing up data to the browser to match the pattern of the template (where the template is either implemented as a static template independent from the CGI script or as a template coded into the CGI script).

If users want to respond to the article, they get a third required page, the follow-up page. The follow-up page is much like the new-post page except that the CGI script has filled in some of the blanks (like subject) to remind users that this is a new article they are writing in the same subject thread. (A subject thread is a topic of discussion with a common subject heading in the articles posted to that list.)

The last bulletin board page is optional. It is the acknowledgment page that comes up after an article is submitted. Several processes are executed to place the new article or follow-up article in the storage area (spool), but there needs to be a "thank you" response and links back into the forum. This page is optional in that the acknowledgment page can simply be the subject index itself.

Web-based Bulletin Boards

Web-based bulletin boards are a popular addition to a Web site. Computer bulletin boards have been around just about as long as the modern personal computer. They are a popular extension of the community formed when users come together to talk about what is important to them.

Much like the Web chat environments we see in sites today, Web-based bulletin boards allow users to engage themselves in the site. They enjoy communicating with other users and sharing ideas and opinions about the issues of the day. There really isn't any limit to the breadth of possible discussion.

There is already a very common and highly sophisticated bulletin board system in exis-tence on the Net today called UseNet. The characteristics of UseNet play a significant role in the development of the Web and the mindset of those who participate in the global electronic community of the Internet.

Note
UseNet is a marvel. It is the product derived from the work of those who needed a free (not monetary), current, and highly organized form of communication. UseNet led to the development of the Web because UseNet introduced the free exchange of information that helped to change the attitudes of the people who pioneered the Web. The Internet is not an information superhighway. It's a dark murky backwater, and UseNet was that backwater. It was hidden and secluded to many, but it was efficient for those who were experienced enough to endure it. The Web is more open and more accessible to the computer novice. UseNet was the precursor to a system of exchanging information across the world freely and making "your ideas" available globally.

What is most characteristic about UseNet when applied to the Web is the idea of storing each article once for many to read. This is a direct relation to the earlier computer bulletin board systems (BBSs) that served the purpose of sharing information among users when there wasn't a Web to browse for information.

Users in a community log into a local BBS and download information that is stored at that particular site. The expansion of the Net and the notion of sharing information between nodes on the Net prompted the formal adoption of UseNet as a popular extension of that practice. UseNet is expanding daily. And like the diverse interests of the Internet community, the various groups you can subscribe to are mind-boggling.

The Web provides access to several kinds of BBSs. Some access is made directly to existing boards, such as UseNet and other premium services (like online newspapers and journals). More and more print icons like the Wall Street Journal are coming online to join the progression (transformation) from print media to online media.

The advantages of putting information online are as follows:

For some ventures, the print media is not economically viable. The costs associated with print are ultimately more expensive than the start-up costs to create an online version of even the most topical releases.

The Web-based bulletin boards introduced in this chapter focus on these opportunities. One goal of this chapter is to show how the effective use of Web-based bulletin boards enhances Web sites. A second goal of the chapter is to provide an example of how to implement a bulletin board structure on the Web. This bulletin board will allow users to read and post messages on specific topics.

WebEmail

This chapter discusses WebEmail, an application that provides a gateway to the pre-existing technology of e-mail. E-mail is a robust mechanism for sharing information. By the standards of the Internet community, it's a technology that is either abused or overlooked by developers as a means to create a patchwork of users who participate in a general discussion.

The Web allows for simplified scanning of e-mail list archives and enables users to only participate in those threads of discussions they are interested in.

Components of a Web-based Bulletin Board

The common element to all Web-based bulletin board is the article itself. The article is the formatted result of a user posting a new message on the bulletin boards.

The four components of the Web-based bulletin board are

  1. The article page
  2. The subject-index page
  3. The new-article page
  4. The acknowledgment page (optional)

Each of these pages is connected logically. For instance, the links generated for the subject-index page are for each of the articles.

Another example is the article page itself. It has links going back to the subject-index page and to the new-article page (for replying or creating a new thread/subject). Article pages should also have Next Article and Previous Article links. If the acknowledgment page is used, then it has links that take the user back to the subject-index page. Figure 30.1 shows the relationships between pages: subject index links to many article pages. Each article page shows who posted it, when they posted it, the e-mail address, the message body, and the link back to the index, link to post-new article, or reply-to article.

Figure 30.1 : This is a diagram showing the associations between the article, subject index, new article, and acknowledgment pages.

To see how each of these pages is generated, we look next at a sample application that builds the pages and connects them together to form the Web-based bulletin board environment.

The New-Article and Article Pages

The new-article page is the page where you ask the user for a new article. The article page is the article itself after it's been posted. Standard elements of the article are

These elements are obtained from the user by the bulletin board application. Users supply the name, subject, and message body of all the articles. When you preserve this information, users don't have to supply their names each time they post a new article in the same session.

The subject line is needed so the Web-based bulletin board software can display some kind of informative text entry on the subject-index page.

And, of course, the message body itself is needed so that there is something worth reading. Articles without a message body should not be allowed to make it into the article spool.

In addition to these elements, an article has several more attributes that are added by the Web-based bulletin board application:

The act of generating the article begins with an HTML form. The steps to create the article are as follows:

  1. The HTML form to accept the user specific information: name, e-mail address, subject, and body of the message.
  2. The CGI script processes this data and constructs a new file (document) that is placed in the spool area holding the other documents that are part of this forum.This CGI script has several tasks to perform:

    Tip
    The CGI script should also check for "sane" input data and tell the user if something he entered is not valid. A simple example is to check the e-mail address to ensure that it is in the form of a standard Internet e-mail address.


  3. Generate HTML.

The act of creating a new article page invokes the CGI script to do the work of building the article file and updating the subject-index page. But the user still needs to see something as an acknowledgment after posting. This is called the "thank you" page because it's typically the acknowledgment of the new message.

The content that appears in the acknowledgment page can be either the subject index itself or another page that says something about being a participant in the forum. It really doesn't matter what you do here.

Typically, though, you'll want to display a copy of the updated subject-index page. And, better still, show the subject-index page highlighting the new article just posted. Users love instant gratification. Seeing their articles up there right after they post them is the ideal situation.

The generation of an article starts from the new-article page. We need an HTML form that allows the user to enter a new article. So the new-article page is an HTML form. In our SimpleBoard application, which implements a simple Web-based bulletin board environment, we use recursive CGI techniques to generate all the pages of the BBS environment and to process the data entered by the user.

Listing 30.1 is a first look at our SimpleBoard application.


Listing 30.1  simpleBoard.cgi-A Simple Web-based Bulletin Board Application

#!/export/home/jdw/perl/bin/perl

@INC = (@INC, '../../lib');
require 'web.pl';

## for bbs.pl

$articleTemplate = "A30A30A40A280";
$SPOOL    = "$ServerRoot/spool";
$bbsLabel = 'SimpleBoard';
$Me = "/cgi-bin/bbs/${bbsLabel}.cgi";

## end bbs.pl


%Form = &getStdin;
&beginHTML("$bbsLabel Application","bgcolor=ffffff");


print "<h1>Chapter 31, $bbsLabel</h1>\n";

if ($Form{'newArticle'} eq 'Transmit') {
  &procNewArticle("$SPOOL/$bbsLabel", %Form);
  &makeSubjectIndex("$SPOOL/$bbsLabel");
}
elsif($Form{'wantArticle'})
{
  &makeNewArticle("$SPOOL/$bbsLabel", $Form{'oldSub'});
}
elsif($Form{'read'})
{
  &readArticle("$SPOOL/$bbsLabel", $Form{'read'});
}
else
{
  &makeSubjectIndex("$SPOOL/$bbsLabel");
}
exit;



sub readArticle {
  local($bbsData, $aid) = ($_[0], $_[1]);
  dbmopen(%bbs, $bbsData, 0666);
  %b = %bbs;
  dbmclose(%bbs);

  @ks = sort keys %b;
  for($i=0;$i<=$#ks;$i++) {
     if ($ks[$i] == $aid) {
         $this = $i;
         last;
     }
  }
 
  @adata = unpack($articleTemplate, $b{$aid});
  print "<h3>$adata[2]</h3>\n",
        "<h4>\n",
        "  Author: <a href=\"mailto:$adata[1]\">$adata[0] &lt$adata[1]&gt</a>\n",
        "</h4>\n",
        "<i>Posted: ", &fixToday($aid), "</i><br>\n",
        "<hr>\n",
        "<blockquote>\n",
        $adata[3],
        "</blockquote>\n",
        "<hr>\n";

  print "<p>\n";

  if ($this >0) {
     print "<i><a href=\"$Me?read=",
           $ks[$this-1], "\">Previous Article</a></i><br>\n";
  }

  if ($this < $#ks) {
     print "<i><a href=\"$Me?read=",
           $ks[$this+1], "\">Next Article</a></i><br>\n";
  }
       
  print "<p>\n";
 
  print "<a href=\"$Me?wantArticle=1\">New Article</a><br>\n",
        "<a href=\"$Me?wantArticle=1&oldSub=$aid\">Respond</a><br>\n",
        "<a href=\"$Me\">Article Index</a><br>\n",
        "<p>\n";

}



sub makeSubjectIndex {
  local($bbsData) = $_[0];

  dbmopen(%bbs, $bbsData, 0666);
  %b = %bbs;
  dbmclose(%bbs);


  &makeSubjectIndexBanner;

  @ks = sort keys %b;
  print "<ol>\n";
  for($i=0;$i<=$#ks;$i++) { 
    @adata = unpack($articleTemplate, $b{$ks[$i]});
    print "<li>",
          "<font size=\"+1\"><a href=\"$Me?read=$ks[$i]\"",
          "<b>$adata[2]</b></a></font>\n",
          "<i><a href=\"mailto:$adata[1]\">$adata[0] &lt$adata[1]&gt</a></i>\n",
          "</li>\n";
  }
  print "</ol>\n";    

  print "<p>\n",
        "<a href=\"$Me?wantArticle=1\">New Article</a><br>\n",
        "<p>\n";
       
}

sub procNewArticle {
  local($bbsData, %fdata) = @_;

  dbmopen(%bbs, $bbsData, 0666);

  $now = $Form{'now'};

  if (! $bbs{$now} ) { 
    $bbs{$now} = pack($articleTemplate, $fdata{'userName'},
                                        $fdata{'userEmail'},
                                        $fdata{'userSubject'},
                                        $fdata{'userBody'});
  }

  dbmclose(%bbs);  
}


sub makeNewArticle {

  local($bbsData, $oldSub) = ($_[0], $_[1]);

  if ($oldSub) {
    dbmopen(%bbs, $bbsData, 0666);
    %b = %bbs;
    dbmclose(%bbs);
    @adata = unpack($articleTemplate, $b{$oldSub});
    $oldSub = ">$adata[2]";
  }

  &makeNewArticleBanner;
  print "<form method=\"post\" action=\"$Me\">\n",
        &button('text', 'userName','Your name: ', '', 30, 1),
        &button('text', 'userEmail','Your Email: ', '', 30, 1),
        &button('text', 'userSubject', 'Subject: ', $oldSub, 40, 1),
        &button('area', 'userBody', 'Message: ', '', 'rows=7 cols=40 wrap=hard', 1), 
        "<p>\n",
        &button('submit', 'newArticle', '', 'Transmit', '', 0),
        &button('reset',  ''          , '', 'Start Over', '', 0),
        &button('submit', 'newArticle', '', 'Cancel',   '', 1),

        "<p>\n",
        &button('hidden', 'now', '', time, '', 1),
        "</form>\n";

}

sub makeNewArticleBanner {

   print "<h2>New Article</h2>\n";

}


sub makeSubjectIndexBanner {
   print "<h2>Subject Index</h2>\n";
}

sub fixToday {

  local($t) = $_[0];
  local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($t);
  sprintf("%02d/%02d/%02d %02d:%02d %s",
          $mday, $mon+1, $year, $hour>12?$hour-12:$hour, $min, $hour>11?"PM":"AM");
}

An article page is generated once a user has submitted a message from the new-article page (see Fig. 30.2). The user is prompted for name, e-mail address, a one-line subject, and the message body. Upon filling in the data, the user can choose to send the article in (Transmit), erase all the entry boxes and start over (Start Over), or cancel (Cancel).

Figure 30.2 : The new-article page.

The SimpleBoard application implements a three-page bulletin board environment. We use only the article page, the new-article page, and the subject-index page. The acknowledgment page is not used and is replaced with the subject-index page. (Recall that the function of the CGI script is to generate HTML, so after we accept the user's message, we generate a new subject-index page.)

The articles are stored in a UNIX DBM file in which each key is the time of day in seconds that the article was posted. The time of day the article was posted is computed the moment the new-article page is generated. We use that hidden data type for comparing against articles already posted. The purpose is to prevent a user from accidentally reposting the same article (by clicking reload on the browser). If two articles have the same post time, the candidate article is dropped.

Note
While possible, it is very unlikely that two users would post at the exact same time. However, one way around this would be to assign a unique random code to go with the time posted in the new-article form. Therefore, an article would only be rejected if the dates/times and the unique code matched.

The new-article page has a cousin. When a user wants to respond to an existing article, the application preserves the previous subject line and automatically fills it in the box for the candidate new-article form.

The Article Spool

The spool is used for storing the articles, while the Perl application, SimpleBoard, organizes them. The file system may appear simpler at first, but having articles in a database allows for simpler sorting, organizing, and manipulating the articles. There are two ways to do this:

The benefit of storing the article with the HTML tags included is that the article doesn't need any other processing to be made display-ready. The function of the CGI script is to generate HTML output and perform system tasks. If the article doesn't need any postprocessing, then it's easier for the CGI to generate HTML. It just loads the document as is from the server.

Storing the articles without any HTML tags implies that there is a method built into the system that puts raw article information together with a template to produce output on a par with the HTML-included version of the article.

The benefit of storing the article without the HTML tags is that changing the look and feel of the articles involves changing a few templates. The effect of a few changes to the global template files means that more time can be spent on making the site look better at any time and making it backward-compatible.

The SimpleBoard application we started with is a mix between these two methods. We don't store the HTML tags with the article data, yet we don't use a template kept in the file system to help format the look of the article pages. The look of the article pages is hardcoded into the SimpleBoard application.

Generating the Index Page

The index page for the bulletin board is the gateway into the whole Web-based bulletin board environment. All the articles that are posted appear in sorted order. The articles are sorted by author's name, subject (subject line), or date posted. Further, the articles are clumped into groups. Some articles are related to other articles on the same subject-that is, they have the same thread.

Threaded bulletin boards are environments in which the appropriate articles are placed together on the index page. Articles on the same subject are listed one after another.

Our SimpleBoard application is not a threaded bulletin board application. The display routine for the subject-index page lists the articles present in the environment sequentially, based on the time of day they were posted. We enhance the SimpleBoard application later in the chapter in Listing 30.2.

Making the SimpleBoard Application Threaded

Now we make a slight change to the SimpleBoard application. The display routine that generates the subject-index page is changed so that the article subjects are threaded.

Threading the article subjects makes the subject-index easier to read, and makes it easier for the user to find the topics that he is most interested in. Figure 30.3 shows the subject-index page showing the threads.

Figure 30.3: There are two threads in this example. Bart wrote an article with the subject "A test." That is its own thread. The other articles are in the "This is a test" thread. The first article is bulleted by the number 2. The follow-up articles are bulleted with the default bullet symbol created by the browser.


Listing 30.2  threadedBoard.cgi-Threaded Version of SimpleBoard Application

#!/export/home/jdw/perl/bin/perl

@INC = (@INC, '../../lib');
require 'web.pl';

## for bbs.pl

$articleTemplate = "A30A30A40A280";
$SPOOL    = "$ServerRoot/spool";
$bbsLabel = 'ThreadedBoard';
$Me = "/cgi-bin/bbs/${bbsLabel}.cgi";

## end bbs.pl


%Form = &getStdin;
&beginHTML("$bbsLabel Application","bgcolor=ffffff");


print "<h1>Chapter 30, $bbsLabel</h1>\n";

if ($Form{'newArticle'} eq 'Transmit') {
  &procNewArticle("$SPOOL/$bbsLabel", %Form);
  &makeSubjectIndex("$SPOOL/$bbsLabel");
}
elsif($Form{'wantArticle'})
{
  &makeNewArticle("$SPOOL/$bbsLabel", $Form{'oldSub'});
}
elsif($Form{'read'})
{
  &readArticle("$SPOOL/$bbsLabel", $Form{'read'});
}
else
{
  &makeSubjectIndex("$SPOOL/$bbsLabel");
}
exit;



sub readArticle {
  local($bbsData, $aid) = ($_[0], $_[1]);
  dbmopen(%bbs, $bbsData, 0666);
  %b = %bbs;
  dbmclose(%bbs);

  @ks = sort keys %b;
  for($i=0;$i<=$#ks;$i++) {
     if ($ks[$i] == $aid) {
         $this = $i;
         last;
     }
  }
 
  @adata = unpack($articleTemplate, $b{$aid});
  print "<h3>$adata[2]</h3>\n",
        "<h4>\n",
        "  Author: <a href=\"mailto:$adata[1]\">$adata[0] &lt$adata[1]&gt</a>\n",
        "</h4>\n",
        "<i>Posted: ", &fixToday($aid), "</i><br>\n",
        "<hr>\n",
        "<blockquote>\n",
        $adata[3],
        "</blockquote>\n",
        "<hr>\n";

  print "<p>\n";

  if ($this >0) {
     print "<i><a href=\"$Me?read=",
           $ks[$this-1], "\">Previous Article</a></i><br>\n";
  }

  if ($this < $#ks) {
     print "<i><a href=\"$Me?read=",
           $ks[$this+1], "\">Next Article</a></i><br>\n";
  }
       
  print "<p>\n";
 
  print "<a href=\"$Me?wantArticle=1\">New Article</a><br>\n",
        "<a href=\"$Me?wantArticle=1&oldSub=$aid\">Respond</a><br>\n",
        "<a href=\"$Me\">Article Index</a><br>\n",
        "<p>\n";

}



sub makeSubjectIndex {
  local($bbsData) = $_[0];

  dbmopen(%bbs, $bbsData, 0666);
  %b = %bbs;
  dbmclose(%bbs);


  &makeSubjectIndexBanner;

  @ks = sort keys %b;

  for($i=0;$i<=$#ks;$i++) {
     @adata = unpack($articleTemplate, $b{$ks[$i]});
     if ($asort{$adata[2]}) {
         $asort{$adata[2]} = join(":", (split(/:/,$asort{$adata[2]})), $ks[$i]);
     }
     else
     {
         $asort{$adata[2]} = $ks[$i];
     }
  }

  print "<ol>\n" if keys %asort;
  foreach $one (sort keys %asort) {
      @nks = split(/:/, $asort{$one});

    for($i=0;$i<=$#nks;$i++) {
        @adata = unpack($articleTemplate, $b{$nks[$i]});
        print  "<li>",
               "<font size=\"+1\"><a href=\"$Me?read=$nks[$i]\"",
               "<b>$adata[2]</b></a></font>\n",
               "<i><a href=\"mailto:$adata[1]\">$adata[0]",
               " &lt$adata[1]&gt</a></i>\n",
               "</li>\n";
        print "<ul>\n" unless $i;
               
      }
      print "</ul>\n";

  }
  print "</ol>\n";

  print "<p>\n",
        "<a href=\"$Me?wantArticle=1\">New Article</a><br>\n",
        "<p>\n";
       
}

sub procNewArticle {
  local($bbsData, %fdata) = @_;

  dbmopen(%bbs, $bbsData, 0666);

  $now = $Form{'now'};

  if (! $bbs{$now} ) { 
    $bbs{$now} = pack($articleTemplate, $fdata{'userName'},
                                        $fdata{'userEmail'},
                                        $fdata{'userSubject'},
                                        $fdata{'userBody'});
  }

  dbmclose(%bbs);  
}


sub makeNewArticle {

  local($bbsData, $oldSub) = ($_[0], $_[1]);

  if ($oldSub) {
    dbmopen(%bbs, $bbsData, 0666);
    %b = %bbs;
    dbmclose(%bbs);
    @adata = unpack($articleTemplate, $b{$oldSub});
    $oldSub = "$adata[2]";
  }

  &makeNewArticleBanner;
  print "<form method=\"post\" action=\"$Me\">\n",
        &button('text', 'userName','Your name: ', '', 30, 1),
        &button('text', 'userEmail','Your Email: ', '', 30, 1),
        &button('text', 'userSubject', 'Subject: ', $oldSub, 40, 1),
        &button('area', 'userBody', 'Message: ', '', 'rows=7 cols=40 wrap=hard', 1), 
        "<p>\n",
        &button('submit', 'newArticle', '', 'Transmit', '', 0),
        &button('reset',  ''          , '', 'Start Over', '', 0),
        &button('submit', 'newArticle', '', 'Cancel',   '', 1),

        "<p>\n",
        &button('hidden', 'now', '', time, '', 1),
        "</form>\n";

}

sub makeNewArticleBanner {

   print "<h2>New Article</h2>\n";

}


sub makeSubjectIndexBanner {
   print "<h2>Subject Index</h2>\n";
}

sub fixToday {

  local($t) = $_[0];
  local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($t);
  sprintf("%02d/%02d/%02d %02d:%02d %s",
          $mday, $mon+1, $year, $hour>12?$hour-12:$hour, $min, $hour>11?"PM":"AM");
}

Changes to makeSubjectIndex()

Listing 30.3 is the changed function makeSubjectIndex() from the SimpleBoard
application.


Listing 30.3  differences.cgi-Differences Between SimpleBoard and ThreadedBoard Applications

sub makeSubjectIndex {
  local($bbsData) = $_[0];

  dbmopen(%bbs, $bbsData, 0666);
  %b = %bbs;
  dbmclose(%bbs);


  &makeSubjectIndexBanner;

  @ks = sort keys %b;

  for($i=0;$i<=$#ks;$i++) {
     @adata = unpack($articleTemplate, $b{$ks[$i]});
     if ($asort{$adata[2]}) {
         $asort{$adata[2]} = join(":", (split(/:/,$asort{$adata[2]})), $ks[$i]);
     }
     else
     {
         $asort{$adata[2]} = $ks[$i];
     }
  }

  print "<ol>\n" if keys %asort;
  foreach $one (sort keys %asort) {
      @nks = split(/:/, $asort{$one});

    for($i=0;$i<=$#nks;$i++) {
        @adata = unpack($articleTemplate, $b{$nks[$i]});
        print  "<li>",
               "<font size=\"+1\"><a href=\"$Me?read=$nks[$i]\"",
               "<b>$adata[2]</b></a></font>\n",
               "<i><a href=\"mailto:$adata[1]\">$adata[0]",
               " &lt$adata[1]&gt</a></i>\n",
               "</li>\n";
        print "<ul>\n" unless $i;
               
      }
      print "</ul>\n";

  }
  print "</ol>\n";

  print "<p>\n",
        "<a href=\"$Me?wantArticle=1\">New Article</a><br>\n",
        "<p>\n";
       
  }

The use of Web-based bulletin boards is varied. There are some well-written applications like hypermail that implement a robust environment for posting articles and following a threaded discussion. The application we present is simplistic in approach; still, it shows the key elements that should be present in all Web-based bulletin board environments.

By transforming the traditional bulletin board applications, we can construct some interesting applications. For example, in Chapter 32, "Classified Pages," we develop a classified-ad application that allows users to post ads. They can even create new classifications.

Although not all those features will be enabled in production environments (environments where the site is in use for the general public), the main theme is that no matter what kind of data is being posted to the board (messages like UseNet, mail like hypermail, or ads), the application has control of the data and the format, and you can write display routines to mold the data into a format specific to the application.