Although use of the World Wide Web is growing by leaps and bounds, the Internet's main use is for electronic mail. E-mail and Usenet News readers allow people who are sending or posting messages to append a signature to the message. This signature (also called a tag line) shows clearly (outside the often garbled header) who sent or posted the message.
This signature, which is usually stored as a text file, gets appended to the bottom of the message; it may look something like this:
-------------------------------------------------------------------- Brad Haasch "Let's go Rangers!" Sams Publishing haasch@execpc.com --------------------------------------------------------------------
This is an easy way to identify yourself to the recipient of your e-mail or the reader of your posting on a Usenet group. It's much easier to figure out who sent what via a signature file than to sort through the often large and confusing header attached to mail and Usenet messages.
Originally, not much went into a signature file, usually one like the following would suffice:
(End of e-mail body) Brad Haasch haasch@execpc.com (End of e-mail)
Then people began to spice up their signatures a bit, add a nifty quote, some cool line art, and before long you might see this:
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ | Brad Haasch "Problems are only opportunities | | SAMS Publishing in work clothes." | | haasch@execpc.com -- Henry J. Kaiser | VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
So, now, not only does the signature convey who sent the message, the sender's title, e-mail address, and often employer's name, it might also include some nifty ASCII line art, and a witty quote.
This chapter discusses how and where signature files are stored and provides an application that accesses a Web page to retrieve quotations that will be placed into your signature file. This allows you to easily generate signature files that not only provide your basic contact information but also provide an interesting quote for the reader of your e-mail or postings.
The storage of signature files varies depending on the operating system on which the e-mail program or newsreader operates. This section describes those locations for both UNIX and Windows operating systems.
For you non-UNIX people, let me explain the placement and use of the signature file. In UNIX, the signature file is held in a file called .signature. The period (.) before the filename indicates that the file isn't important to the everyday UNIX user on a day-to-day basis, and that on a directory command (ls in UNIX), these period files are skipped, as you can see in Figure 13.1.
Figure 13.1. The average user's UNIX home directory.
As you can see no files that begin with a period (including the .signature file) appear, but we know they exist. Add the -a flag to the ls command to see these period files, as shown in Figure 13.2.
Figure 13.2. UNIX home directory exposed with ls -a.
Here you see a bunch of UNIX user files that take care of things such as login scripts, e-mail, subscribed newsgroups, and so on. The file we're concerned about is .signature.
Now that Windows e-mail programs working via a PPP connection have come to market and have gained wide use, the signature file is stored in a different place for each different e-mail program.
For instance, Eudora stores your signature file in a file called signatur.pce in the root Eudora directory. These files are standard text, so you can generate a replacement for signature files quite easily.
By using Yahoo (http://www.yahoo.com), I searched for tag lines. The first site returned by Yahoo was named Tag Lines Galore and is described in the next section. Some other sites that have quotes suitable for this type of application are also featured in the following sections.
http://www.brandonu.ca/~ennsnr/Tags/Welcome.html
This is the root of several quote pages. One has a different set of 100 random quotes every day. This site also includes the computer archive, which is used in the application presented here, as well as other sites.
Every time this page is reloaded, it not only provides you with a new quote from the great Vulcan himself, but a nifty picture as well.
http://spidey.usc.edu/www-bin/quote
This is another CGI script that returns a random quote. This script was produced by Andrew N. Marshall at the University of Southern California.
http://www.hooked.net/users/davew/bin/stevenwright
http://www.hooked.net/users/davew/bin/deepthoughts
Provided by davew@hooked.net, these two URLs are for obtaining a Steven Wright quote and bringing you a 'deep thought' from Jack Handy.
http://www.nova.edu/Inter-Links/quotes.html
This site, maintained by Andrew Tong, has several anchors to quote sites.
Keep in mind you should get the permission of the site Webmaster to use such a site in any applications. Imagine the Webmaster who finds his access logs go from 100 hits per day to a few thousand due to a distributed application using his site as a source for quotes.
Due to the difficulty of coming up with a witty quote, I present a program that will, given user information, connect to a Web site, pick out a quote at random, and write a new signature file to the user-specified location.
The program provides space for users to enter their name, e-mail address, and title. With that information in place, the program will present the quote, get a different one if the user doesn't like the one suggested, and then allow the user to save the new signature file.
The signature generator program goes through these steps:
To start, you'll design the user interface to include the following: textboxes with labels for the user information and the suggested quote; command buttons to connect to the quote server or grab a different quote if the first one isn't acceptable; a button to save the file; and an exit button.
The other controls you'll use are the common dialog for saving the file, the dsSocket control from Dolphin Systems for connecting to the Web server and retrieving the information, and a listbox for holding the complete list of quotes. Figure 13.3 shows the arrangements of the elements for the E-Mail Signature Generator application.
Figure 13.3. Design-time view of the application.
You can start by examining the code to configure and use the dsSocket control. This control is used to connect to the Web server and then to retrieve the quotes. In the Form_Load procedure, the following lines define some of the properties of the dsSocket control:
dsSocket1.RemoteHost = "www.brandonu.ca" dsSocket1.RemotePort = 80 dsSocket1.LineMode = True dsSocket1.EOLChar = 10
The RemoteHost property of the dsSocket control is set to the server name, not the URL of the quotes. The URL is specified later when you issue the GET command to the server. The RemotePort is specified to 80, which is the default of the control, and the standard port that is used for HTTP communications. The LineMode property is set to True, indicating that the dsSocket control will trigger the receive events when the EOL character (defined by dsSocket.EOLChar) is reached. The EOLChar property is set to 10, which is the ASCII code for the linefeed character.
To actually retrieve the page, you must issue a command to the Web server specified in the dsSocket's properties. The command button cmdGo (captioned Connect to Server) contains the following lines of code:
dsSocket1.Connect dsSocket1.Send = "GET /~ennsnr/Tags/COMP_hype.html" & vbCrLf & vbCrLf
The Connect method of the dsSocket property connects the control to the specified Web server. Then use the Send method to issue a command to the Web server.
GET, followed by the URL, requests that document from the server. The two carriage return/linefeed combinations issue the command.
Once the request is sent, the server starts sending back the contents of the requested URL. This fires the Receive event of the dsSocket control. The code for the Receive event is
list1.AddItem ReceiveData list1.ListIndex = list1.ListCount - 1
The line received is added to the hidden listbox on the form, and the index is set to the next usable value (list1.ListCount -1). The Receive event fires repeatedly, adding each line of the URL to the listbox, until the page is completely downloaded.
Now that you have a list of Quotes and a few HTML tags in your listbox, you can choose one at random and place it in the txtQuote textbox, with the following code:
num_quotes = list1.ListCount - 18 Randomize random_quote_index = Int((num_quotes * Rnd) + 11) list1.ListIndex = random_quote_index iTemp1 = Len(list1.Text) txtQuote = Left(list1.Text, iTemp1 - 1)
You subtract 18 from the list count to account for the number of lines that are used for HTML tags. This varies depending on the site you use as a source for quotes. You then initialize the random number generator and choose a random number based on the modified list count. With this, you copy the selected line into the txtQuote textbox, removing the last character, which is the vertical bar, representing the linefeed character.
With the first quote in place, the user then can select different quotes by repeatedly pressing the Get Quote button. This action chooses another random number within the constraints of the modified list length and displays that quote.
After the user has settled on a quote and entered his or her name, title, and e-mail address, the user can press the Write File button to save the new quote to disk.
The code to format the user information and the quote is a good example of string manipulation in Visual Basic.
The desired format for the signature is
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- User Name User Title "Insert cute quote here" User E-Mail -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Or, if the quote is too big to fit on one line:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- User Name "Insert cute quote here, but it's long, so we'll User Title have to use part of the second line also." User E-Mail -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
The code to do this is rather involved. Let's start with the first and last linesthe alternating -= pattern to offset the signature from the message. These lines create the pattern:
For x = 1 To 40 sTemp1 = sTemp1 & "-" sTemp1 = sTemp1 & "=" Next x
This generates a separator line 80 characters long, of minus and equal signs.
Two different cases you have to take into account are when the quote fits on one line, and when a quote requires two lines.
You may be wondering about long quotes that would take three or more lines. Because this is an Internet book, not a string processing book, I only cover up to two-line quotes. However, it's not a horrible task to convert my code that breaks a quote into two lines into a routine that would handle three- or four-line quotes as well.
To know if you need to break the quote apart, you need to know the length of the longest user field. The code to determine that is a series of If-Then blocks:
left_min = Len(txtUser(0).Text) + 6 If left_min < Len(txtUser(1).Text) Then left_min = Len(txtUser(1).Text) + 6 End If If left_min < Len(txtUser(2).Text) Then left_min = Len(txtUser(2).Text) + 6 End If
The txtUser(0) through txtUser(2) textboxes correspond to the name, title, and e-mail address of the user. The six is added to the left_min value as an offset. Later, you'll use the left_min as a starting point for the starting character of the quote for that line, and the six spaces provide some room between the longest user field and the quote.
Now that you know how much room is taken up on the left side by the user information, you can look at the length of the string and see if it needs to be broken apart. You can handle each case and format the strings used for output:
quote_len = Len(txtQuote.Text)
quote_len is used as a placeholder for the length of the quote. Then you check against the value given by 80 - left_min. left_min is the number of characters the longest user information field uses; eighty is the total number of columns available. The difference becomes the amount of available characters per line for the quote.
If (quote_len > (80 - left_min)) Then
If this condition is satisfied, you need to break the string into two parts. You start by finding the first space that occurs after the halfway point in the quote:
iTemp2 = (quote_len / 2) iTemp2 = InStr(iTemp2, txtQuote, " ")
You then copy the first part to subStr1 and the second part to subStr2:
subStr1 = Left(txtQuote, (quote_len - iTemp2)) subStr2 = Right(txtQuote, iTemp2)
Now you can build the strings used for user output. sTemp1 contains the top and bottom separator bars (-=-=-=--=). sTemp2 holds the user's name and first line of the quote if the quote is multiline.
The same procedure for the first line is applied to the secondthis time using the user's title and the second half of the quote, as follows:
sTemp3 = txtUser(1) sTemp3 = sTemp3 & Space(left_min - Len(txtUser(1))) sTemp3 = sTemp3 & substr2
The Else condition, in this case, generates the strings for a one-line quote It first gets the user's information, then adds the whitespace padding, and finally the quote:
Else 'sTemp2 gets the user name... sTemp2 = txtUser(0) 'sTemp3 gets the title... sTemp3 = txtUser(1) sTemp3 = sTemp3 & Space(left_min) sTemp3 = sTemp3 & txtQuote.Text End If
That's all there is to it. Now that the strings for the signature are formatted, all you have to do is write them to disk.
The time has come to write the signature to a file. The following code shows just how easy it is to do this using the common dialog control and simple file I/O code.
commondialog1.filename = "" commondialog1.ShowSave If commondialog1.filename = "" Then Exit Sub Open commondialog1.filename For Output As #1 Print #1, sTemp1 'border Print #1, sTemp2 'name + quote if 2 line quote Print #1, sTemp3 'title + quote Print #1, sTemp4 'e-mail address Print #1, sTemp1 'border again Close #1
You use the check on a zero-length filename to see if the user pressed Cancel. If not, open the file as text, write to it, and close the file.
Timing is everything, and event-driven programming drives that fact home. You might have noticed and wondered when looking at the form, "What happens if the user clicks on Get Quote before clicking on Connect to Server?" Because one is dependent on the other, set the Enabled property of the GetQuote to False at form load, and on the Click event of the Connect to Server button, set it back to True. This ensures that no error occurs due because a connection to the Web server wasn't made first.
One limitation of this program is that, if it were to be distributed, the server name and URL are hard-coded. The application also assumes that there won't be any HTML tags within the body of quotes, and the HTML tags take up approximately the first 10 lines and the last 8 lines of the file.
You could, instead, use a dropdown list box filled with known quote sites. The sites you choose should have a consistent format for displaying the quotes so your code can pick them out. Then, when the user selects a different site from the list, your code would adjust the expected formatting in order to retrieve the quote correctly. See the section titled "Selecting and Formatting the Quote" above for the code that you'll have to modify to make this change.
Another potential shortcoming is handling server-returned error messages that are returned as HTML files. The possible error codes and messages are discussed in Chapter 2, "HTTP: How To Speak On The Web." One way to handle errors is to have an expected listcount number, and if the number returned is substantially less than that number, to show the user an error message.
This is a basic example of using Web-based information to provide an added service to the end user. By incorporating the Web into the application, updates to the quote database can be made, and the user can take advantage of them, without modifying the client program. Programs that use information such as stock quotes (Chapter 13, "QuoteWatcher: An Interactive Web Agent"), book prices (Chapter 14, "BookShopper: An Agent for Searching Online Booksellers"), and other information subject to change can greatly benefit from hosting the data on a Web server rather than distributing database files on a periodic basis.