Enlisting Java in the War Against Email Viruses
Java Programming Notes # 2180
- Preview
- Operational Discussion
- Program Code
- Run the Programs
- Summary
- What's Next?
- Complete Program Listing
Preview
Consider the following scenario. To use the common jargon, you decide that it is time "check your email." This produces a list of about twenty messages on the screen in your favorite email client program. By quickly scanning the list, you conclude that about half are SPAM and the other half are important messages from business associates.
The good news
You also notice that there is a message from an old friend that you haven't heard from in awhile, so you decide to open and read that message before getting down to the business of the day.
The bad news
You double click on message from your friend. However, before it becomes readable, your virus program pops up a dialog box telling you in effect that it has found a virus in the message and that it was unable to clean the file. Therefore, it has quarantined the file, making it inaccessible.
Shucks, you say to yourself, making a mental note to call your friend later in the day to tell him that he sent you a message containing a virus.
Why did your friend send you a virus?
Your friend probably didn't purposely send you a virus. Rather, your friend's computer has probably become contaminated with a virus that is replicating itself by sending virus messages to everyone in your friend's email address book. Even messages from trusted friends can't be trusted.
Now for the really bad news
When you attempt to open and read one of the important business messages that you have just received, you discover that it is also inaccessible. You quickly discover that every message in your inbox, including the important business messages, has become inaccessible.
How can this happen?
Only one message contained a virus. Why did all of the messages in your inbox suddenly become inaccessible?
The answer is simple once you understand it
Many email clients present you with a display that looks much like the display of folders containing files on your disk. The email client allows you to organize your messages by storing them in folders, one of which is often named inbox. The visual suggestion is that each message is a separate file, where groups of related files are contained in folders or directories on the disk.
Looks can be misleading
However, with many email clients, looks can be misleading. Many email client programs combine groups of related messages into a single file. With Netscape Communicator, for example, there really is no folder on the disk named inbox. Rather, there is a single file named inbox, and all the messages in your inbox are concatenated into that single file.
(If you are interested in detailed format information for files of the type used by Netscape Communicator, go here.)Many messages in each file
Netscape Communicator concatenates all of the messages that you store in each mail folder into a single file whose name matches the name of the folder. Then they create another file with a similar name that provides an index into the file containing the messages. They put these files into an actual disk folder deep inside the directory tree that contains lots of Netscape material.
(The organization is actually somewhat more complicated than this, but hopefully you get the idea. Individual messages are not in individual files with Netscape Communicator.)Other email clients behave similarly
Although I don't have any personal experience to confirm this, I've been told that other popular email clients group messages into files on an even larger scale, possibly causing multiple mail folders and their messages to be included in a single file.
Virus checker configuration
When I configure "File System Realtime Protection" for my virus checker, I have the following options:
Primary Action when a virus is detected:
- Clean virus from file
- Quarantine infected file
- Delete infected file
- Leave alone (log only)
- Quarantine infected file
- Delete infected file
- Leave alone (log only)
I have my virus checker set to the first choice in both cases, (which is the default configuration). Therefore, if my virus checker is unable to clean a virus from my inbox file, it is well within its rights to quarantine the entire file. Unfortunately, that causes all the messages currently in the inbox to become inaccessible.
(The only good news at this point is that you can still identify the senders. You can send a message to those parties asking them to send you another copy of the message.)An even worse scenario
At worst, the above scenario will cause you to lose a few email messages, most of which are probably recoverable by requesting another copy from the sender.
Now consider another scenario that can potentially cause you to lose vast amounts of critical business information, unrelated to email messages.
You avoided quarantine
Assume that somehow you managed to keep the virus checker from putting your inbox file into quarantine when you received a message containing a virus. (Perhaps you had it turned off at the time).
You have learned not to open email attachments that you weren't expecting. While reviewing the subjects of the messages in the inbox, you noticed the suspicious message carrying the virus, and you simply deleted the message containing the virus without opening it.
Another surprise may be in store
At least for users of Netscape Communicator (and probably other products as well), when you "delete" a message, it really doesn't get deleted from the system. Rather, it simply gets moved into another folder (file), typically named Trash.
Always do your backups
Before leaving work that day, without "emptying the Trash" in your email client, you dutifully perform an incremental backup, which saves all the material on your disk that has changed since the last incremental backup. Guess what? The Trash file has changed. You saved it. It contains a virus, and you have just created an incremental backup file containing a virus.
You may catch it the next time you scan
If you leave a copy of the incremental backup file on your disk, the next time you do a full virus scan on the disk, you will be notified that the incremental backup file contains a virus. Depending on several factors, that incremental backup file may or may not have been rendered worthless for restoration purposes. When an incremental backup file is rendered worthless, the entire backup scheme is rendered worthless.
You are lucky if it turns out this way. The solution is to empty the trash in your email client and start a new backup series beginning with a full backup.
You may not be so lucky
Even worse, you may not have left a copy of the incremental backup file on the disk, and the first time you learn that it contains a virus may be when you try to use it later to restore your data after a disk crash. That is a very bad time to learn that an email virus has rendered your backup scheme worthless for restoration purposes.
With this scenario, a simple email virus can cause you to lose vast amounts of critical business information.
And worst of all
And perhaps worst of all is the case where you accidentally allow an email-borne virus to get lose inside your computer. When this happens, the virus can begin replicating itself on every computer on your in-house network, not to mention sending itself to all of your customers whose email addresses are contained in your address book.
Why am I telling you this?
I am telling you this to drive home the point that email-borne viruses can be far more serious than just being a nuisance. Not only can they cause you to lose important business email messages, they can also cause you to lose a wide-ranging variety of business information in the event of a need to restore business data from backup files.
(Because of this possibility, I no longer do incremental backups, even though they are much faster to do. I'm not certain of the correct name for this procedure, but each time I do a backup, I save every file that has changed since the full backup that began the series. Thus, only the first and last backup files are required to completely restore the system.No virus messages allowed
In addition, I regularly scan my backup files for viruses. If I find that my latest backup file contains a virus, I can delete the virus from the disk and do another backup on everything that has changed since the full backup. That gives me a way to recover without having to start over.)
As illustrated above, it is extremely important that you don't allow messages with viruses to get into your email data structure. The purpose of this article is to show you one way to accomplish that goal.
A simple and inexpensive scheme
The scheme that I will describe is very simple and also very inexpensive. The resources required consist of three computer programs and two email accounts, one public and one private.
(By private, I mean a secret email account known only to you. You must not divulge the email address on the account to anyone, including your best friends. It is extremely important that your secret email address never exist in the email address book on any computer anywhere in the world. This is particularly true for address books belonging to trusted friends whose email messages you are most likely to read.)A second email account
A second email account may cost you two or three dollars per month, if it costs you anything at all. Many ISPs provide you with several email accounts at no extra charge.
Two of the programs are free
Two of the required programs are free, because I am going to publish them in this article. The third required computer program is a good virus checker program, which you should already have anyway.
The operational scheme
The operational scheme is very simple. For now, let's call the two programs that I will provide program A and program B.
You never use your email client program to download email messages from your public email account. Rather, you run program A to download the messages for you.
A separate file for each message
When you run program A, it will download all of the messages on the server and write each of those messages into a separate file in a specified folder on your disk. It is important to note that at this point, the messages are still separated from one another. A virus in one message cannot corrupt another message.
(On my system with a cable modem, I can download one hundred messages in just a few seconds, so this process is very fast.)Scan the message files for viruses
Next you use your virus checker program to scan all of the message files in that folder, either cleaning or removing any that contain a virus.
(My advice would be to totally remove the contaminated file to avoid any possibility of creating an invalid message format in the file. )On my system, which is relatively slow, only a few seconds are required to scan one hundred messages.
Now forward the remaining clean messages
The next step is to run program B, which forwards the remaining messages to your secret email account. If you did the virus check (and you keep your virus checker program up to date), all of these messages should be free of viruses.
This process takes a little longer than the other two. My system, running through a cable modem, requires about three or four seconds to forward each message. Thus, one hundred messages require five or six minutes to forward.
No need to wait
However, you don't have to wait until the third step described above is complete to view your messages. Simply open your email client program and start downloading and reading messages from your secret email account.
As soon as the first message has been forwarded to the secret email account, it is available for downloading and reading. For the next few minutes, messages will be forwarded to your secret email account much faster than you can possibly read them.
Worth the extra time and effort
Unless you have a very large number of messages, a very slow computer, or a very slow Internet service, the steps required before you can start reading your messages should take less than a minute to complete. This is a small price to pay for assurance that your email data structure is free of viruses.
Viewing tip
You may find it useful to open another copy of this lesson in a separate browser window. That will make it easier for you to scroll back and forth among the different listings and figures while you are reading about them.
Supplementary material
I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find those lessons published at Gamelan.com. However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there. You will find a consolidated index at www.DickBaldwin.com.
Operational
Discussion
The operation of each of the two programs is very simple. The
names of the two programs are VirPro01a and VirPro01b,
corresponding respectively to program A and program B in the
hypothetical case discussed above.Starting the program named VirPro01a
Once you have a compiled version of VirPro01a on your system, and you have created a working directory, you start the program running by entering the following at the command line (for convenience, I use a batch file with a shortcut on the desktop to accomplish this):
java VirPro01a pubServer userName password
The command line parameters identify your public email server, your user name, and your password on that email server. (This is the same information that you normally provide when setting up an email client program.)
This information makes it possible for the program to connect to your public email server and to download the messages currently stored there.
(If you are uncomfortable with this handling of the password, you could modify the program to elicit the password at runtime. See JPasswordField in the Java documentation.)The user interface for VirPro01a
Figure 1 shows the user interface for VirPro01a. This simple interface consists of a button and a text area.

Figure 1 VirPro01a user interface
You start the download by pressing the Start button. Information is displayed in the text area as the program executes. Figure 1 shows that the program has downloaded fifty messages, (with corresponding message numbers), from the public email server.
The working folder named Messages
As you will see when we examine the code for VirPro01a, with my setup, these messages are stored in a folder named Messages. However, you can modify the program to store them anywhere you choose.
(Note that no messages are deleted from the email server by the program named VirPro01a.)Run the virus checker
After VirPro01a finishes downloading the messages and storing them in individual files, the next step is to run your virus checker on all the files in the working folder, removing any that contain a virus.
Starting the program named VirPro01b
Once you have a compiled version of VirPro01b on your system, and you have created an archive directory in addition to the working directory, you start the program named VirPro01b by entering the following at the command line (with no line breaks):
java VirPro01b pubServer userName password secretServer smtpServer
In this case, the command line parameters identify:
- Your public email server
- Your user name on the public server
- Your password on the public server
- Your secret email address
- The SMTP server on which you are authorized to send email messages.
What is this information used for?
This information makes it possible for the program to:
- Forward the clean email messages from the working folder (named Messages in my case) to your secret email account.
- Delete the corresponding messages from the public email server once they have been forwarded to the secret email account.
(You will probably want to delete the message files from the archive folder periodically to free up disk space.)Why have an archive folder?
With my setup, I tag the subject line of each forwarded message with the sequential message numbers from the public email server. (You can modify the program to substitute any tag that you choose, including no tag at all.) Tagging with message numbers makes it easy for me to confirm that every message arrived safely at the secret email account.
If a message doesn't show up ...
In the unlikely event that a message fails to be successfully forwarded to the secret email account, there is a backup copy in the archive folder. You can view the backup copy with an ordinary text editor.
If the message was composed in plain text, you will be able to read it in its entirety using a text editor.
If the message was composed using HTML text, you will be able to read it using a text editor, but you will have to ignore the HTML tags.
SPAM messages
If the message is a SPAM message, it is not likely that you will be able to make much sense out of it with a text editor. It will probably contain fairly complex HTML code with hundreds of random words, phrases, and sentences inserted to thwart automatic spam blocking software. In addition, the HTML will probably contain links to various web sites where most of the substance of the SPAM message is presented. If you really want to read it, however, you can probably copy the HTML, paste it into an empty HTML file, and open it in your browser.
Base64 encoding
If the message was composed in non English characters using Base64 encoding, you won't be able to read it at all without running it through a Base64 decode program.
(I have published other tutorials that explain how to do Base64 decoding using the sun.misc.BASE64Decoder class. You can also search for information about Base64 decoding on Google.)Keeping a backup copy of the message
In any event, I consider it a good idea to keep a backup copy of the message files for a couple of days after forwarding them to the secret email account, just in case I need them for some reason.
The user interface for VirPro01b
Figure 2 shows the simple user interface for VirPro01b.

Figure 2 User interface for VirPro01b
The user presses the Start button to cause the message forwarding process to begin.
The screen shot in Figure 2 was captured at the point where seven of the fifty messages from Figure 1 had been forwarded to the secret email account.
Once all of the messages in the working directory have been forwarded to the secret email account, the Delete button is enabled. This makes it possible for the user to delete the messages from the server, and to cause the corresponding message files to be moved from the working folder to the archive folder.
Another safety feature
If the communication portion of the program detects any problems (throws any exceptions) in forwarding a message, that message will not be included on the list of messages to be deleted from the server and moved from the working folder to the archive folder. Thus, when the deletion operation is complete, those message files will still be on the server and will still be in the working folder.
You can rerun VirPro01b in another attempt to forward the remaining messages. Depending on the nature of the problem (such as a timeout due to network congestion), the second attempt to forward a message may or may not be successful.
(I have found this to occur occasionally under very poor network conditions.)
Program Code
Program VirPro01aI will begin by explaining the program code for the program named VirPro01a. Portions of this discussion will be very brief because I have previously explained similar code in a lesson entitled Enlisting Java in the War Against SPAM, Part 1, The Communications Module.
The VirPro01a program is designed to be used with a POP3 email server as the public email server.
(The server for the secret email account can be of any type for which you can obtain a message viewer. For example, it could be a typical WebMail server.)For technical information on the POP3 message transfer protocol, see RFC 1725 at
http://www.cis.ohio-state.edu/htbin/rfc/rfc1725.html.
This program was tested using SDK 1.4.2 under WinXP.
Will discuss in fragments
As is my custom, I will discuss the program in fragments. A complete listing of the program is provided in Listing 40 near the end of the lesson.
Instance variables
The beginning of the VirPro01a class, and a list of instance variables are shown in Listing 1.
class VirPro01a extends Frame{ |
You might want to use a different folder for this purpose. If so, simply provide the path and folder name as a String. As you can see, my working folder, named Messages is specified relative to the folder that contains the class files for the program. You could use an absolute path rather than a relative path if you choose.
The remaining instance variables in Listing 1 are simply working variables used by the program for various purposes.
The main method
The main method, shown in Listing 2, confirms the correct number of command line parameters, and uses those parameters to instantiate an object of the VirPro01a class.
public static void main(String[] args){ |
The constructor begins in Listing 3.
VirPro01a(String server,String userName, |
This code is almost identical to the code that I explained in the earlier lesson, so I will let the comments in Listing 3, plus the discussion in the earlier lesson suffice.
A WindowListener
Listing 4 uses an anonymous class to instantiate and to register a WindowListener object to service the close button in the upper right corner of the Frame in Figure 1.
this.addWindowListener( |
Final local variables
Listing 5 declares and initializes two local variables in the constructor.
final Button startButton = |
(Note that these two local variables must be marked final because they are accessed by code defined in an anonymous class. Code in an anonymous class or a local class cannot access non-final local variables.)Register an ActionListener
Listing 6 shows an anonymous class used to instantiate and register an ActionListener object on the button.
startButton.addActionListener( |
While the code in Listing 6 is not identical to the code that I explained in the earlier lesson, it is very similar, and some less complex. Therefore, if you understood the code in that lesson, you should have no difficulty understanding the code in Listing 6.
Configure the GUI
Listing 7 configures the GUI by placing the various components in the Frame, setting the size of the Frame, and making it visible.
add(startButton); |
The validateOneLine method
The complete program, shown in Listing 40 near the end of the lesson also contains a utility method named validateOneLine. This method is identical to the method having the same name that I explained in the earlier lesson. Therefore, I won't bore you by repeating that explanation here.
And that is the end of the class named VirPro01a. As you can see, it doesn't contain much new material relative to my earlier lessons.
Program VirPro01b
That brings us to the program named VirPro01b, which contains a great deal of new information relative to my earlier lessons.
As described earlier, this is one of a pair of programs designed to be used together, in conjunction with a good virus scanner program to prevent messages with viruses from contaminating an email inbox.
This program should be run after the program named VirPro01a has been run, and a virus checker has been used to confirm that the files produced by VirPro01a are free of viruses, or that any such files containing viruses have been removed from the working folder (hopefully either deleted or quarantined).
This program forwards email messages to a secret email account. On my system, which is relatively slow, using a cable modem, about three to four seconds are required to forward each message.
This program was tested using SDK 1.4.2 under WinXP.
The forwardEmailMsg method
I'm going to begin by explaining what may be the most complex part of this program. That is a method named forwardEmailMsg. Part of what makes this method complex is that it depends on the largely undocumented Sun class named sun.net.smtp.SmtpClient.
This is a very useful class for sending email messages, and it is included in SDK version 1.4.2. However, it doesn't seem to be included in the SDK 1.4.2 documentation, and it is very difficult to find much in the way of documentation for this class.
Where is the documentation?
About the best that I have been able to find in the way of documentation can be found at http://swig.stanford.edu/pub/java/javadoc/sun/net/smtp/SmtpClient.html.
The operational description of the class on the above web site reads as follows:
" This class implements the SMTP client. You can send a piece of mail by creating a new SmtpClient, calling the "to" method to add destinations, calling "from" to name the sender, calling startMessage to return a stream to which you write the message (with RFC733 headers) and then you finally close the Smtp Client."Very little descriptive information
Other than the brief description given above, the documentation provides very little in the way of descriptive information. However, it does provide such crucial information as method names, parameter types, return types, etc.
Many cautions
If you search the Web for information about this class, you will find numerous cautions about using it, most of which are based on the fact that it is reportedly not supported by Sun. If you are working on a product that will require long-term support and maintenance, that is probably a genuine concern. However, I wrote this program largely for my own use in protecting myself against email viruses. Therefore, I'm not concerned about long-term support and maintenance. The class is easy to use, and therefore seems to be a pretty good choice for this purpose.
The readLines method
The forwardEmailMsg method uses another method named readLines. Therefore, I will explain the readLines method before embarking on an explanation of the forwardEmailMsg method.
The readLines method begins in Listing 8.
private String readLines(String pathFileName, |
This method receives the following three String parameters.
- pathFileName
- firstLine
- lastLine
The readLines method reads and saves lines of text from a text file starting with the line that starts with firstLine and ending with the line that starts with lastLine.
If lastLine is null, data is saved to the end of the file.
If firstLine is null, data is saved beginning with the first line in the file.
The lines of text from the file are saved by concatenating them into a single String object with a newline inserted into the string at the end of each line.
The name and path to the file is given by pathFileName.
The remainder of the method
The remaining code in the readLines method is shown in Listing 9.
StringBuffer strBuf = new StringBuffer(); |
Don't confuse the name of this method with the readLine method of the BufferedReader class used internally in Listing 9.
Otherwise, the code in Listing 9 is very straightforward and shouldn't require further explanation.
The format of a message
While I designed the readLines method to be fairly general in nature, I did design it with the task of extracting text lines from raw email messages in mind, so it may be useful for you to see an example of such a message.
Figure 3 shows the raw text for a very simple email message that I sent to myself for purposes of illustration. (Note that I had to manually insert a large number of line breaks in the text to force it to fit into this narrow publication format.)
Return-Path: <Baldwin@DickBaldwin.com> |
The Subject line and the Status line
The Subject line will figure prominently in the code in the forwardEmailMsg method. In this version of the program, the message number is inserted into the Subject line before the message is forwarded to the secret email account.
The Status line and everything above it is considered to be the message header. Everything below the Status line is considered to be the message body. If you find yourself reading the raw text of an email message with a text editor, you will usually want to concentrate on the body of the message.
Back to the forwardEmailMsg method
The forwardEmailMsg method begins in Listing 10.
private boolean forwardEmailMsg( |
- recipient - Email address of the person that is to receive the message. In this case, it is the email address of the secret email account. This is one of the command line parameters when the program is started.
- smtpServer - Identification of an smtp server on which you are authorized to send email messages. This is one of the command line parameters when the program is started.
- tag - A string that is inserted at the beginning of the Subject before forwarding the message to the recipient. I used the original message number from the public email server, but you could change this to something else if you choose.
- pathFileName - Identification of the message that will be forwarded to the secret email account.
Listing 11 declares and initializes a local variable that will be used later in the method.
StringBuffer message = new StringBuffer( |
The documentation identified earlier identifies two overloaded constructors for the class:
- One that creates an uninitialized SMTP client.
- One that creates a new SMTP client connected to a specified host.
try{ |
The from() method
Although the documentation identified earlier doesn't provide a description of this method, it can be deduced intuitively (and from the brief description at the beginning of the documentation) that this method needs to receive the email address of the sender of the message.
smtp.from(recipient); |
In this case, it really doesn't matter who the email message is sent by, provided that it is a possible email address. The email client program at the secret email account will interpret the From: line in the header of the message as the sender of the message.
(It is necessary, however, that the email address passed to the from method be a possible email address. Otherwise, the from method will throw an exception.Since we know that the recipient's email address is a possible email address, the recipient's email address was passed to the from method as the sender of the message.
You might reasonably ask why the from method exists if it doesn't matter. The email address that you pass to the from method will show up in the line that begins with Return-Path in the message header. See Figure 3 for an example.)
(If the header doesn't contain a From: line, which happens occasionally, the SmtpClient object will construct a new header showing the recipient as the sender, and insert this new header at the beginning of the message.)The to() method
This method needs to receive the email address of the intended recipient of the message.
The code in Listing 14 passes the recipient's email address to the to() method.
smtp.to(recipient); |
This method gets and returns a PrintStream object that is used to construct the message.
PrintStream msg = smtp.startMessage(); |
Get the entire message as a String
The code in listing 16 invokes the readLines method to get the entire message from the file pointed to by pathFileName and to convert that message to a single String object.
message = new StringBuffer(readLines( |
(See Figure 3 for an example of the contents of a raw message file.)Insert the tag into the Subject line
The code in Listing 17 performs the following actions:
- Inserts the value of the incoming parameter tag into the Subject line immediately before the current body of the subject.
- Converts the message from a StringBuffer object to a String object and invokes the println method to insert it into the output stream.
message = message.insert(message.indexOf( |
The code in Listing 18 invokes the closeServer method on the SmtpClient object.
//Close the stream and send the message |
Return true on success
Then the code in Listing 18 returns true. This notifies the calling method that the message has been sent, and that it is all right to delete the message from the server and to move it from the working folder to the archive folder.
Exceptions
If any of the SmtpClient methods called in the forwardEmailMsg method throws an exception, it will be caught by the catch block in Listing 18.
This catch block prints some diagnostic information, beeps to alert the user, and then returns false. This is a signal to the calling method that the message has not been forwarded, should not be deleted from the public email server, and should not be moved to the archive folder.
Depending on the exact nature of the exception, it may or may not be useful to rerun VirPro01b in an attempt to send the message. If the cause of the exception was a simple timeout due to heavy network traffic (or due to the SMTP server going down), there is a good chance that a rerun will be successful in sending the message the second time around. For other more serious problems (such as a seriously malformed message), a rerun might not be successful and the message file becomes a candidate for examination with a text editor as described earlier.
The moveFile method
There is one other utility method that I will discuss before getting into the details of the constructor for the VirPro01b class. Listing 19 shows the moveFile method in its entirety.
private void moveFile(String pathFileName, |
This method receives two incoming parameters:
- pathFileName - Current location and name of a file.
- archivePath - Destination of the file.
The reName method of the File class returns true if the operation is successful and false otherwise. For example, if a file with the same name already exists in the destination folder, the operation will fail, and the code in Listing 19 will print a message indicating that the move was not successful.
The VirPro01b class
Listing 20 shows the beginning of the VirPro01b class along with the declaration and initialization of some instance variables. The comments in Listing 20 explain the use of the instance variables, so I won't elaborate further on them.
class VirPro01b extends Frame{ |
(Be sure to create the new folders that you specify before attempting to run the program.)The main method
The main method is shown in its entirety in Listing 21.
public static void main(String[] args){ |
The constructor for the VirPro01b class
The constructor begins by storing the secret email address in the instance variable named recipient to make it available to other methods of the class. The other incoming parameters are used only within the constructor, so there is no need to save them as instance variables.
VirPro01b(final String server, |
A WindowListener object
The code in Listing 23 defines an anonymous class, and instantiates an anonymous object of that class that implements the WindowListener interface.
this.addWindowListener( |
The GUI components
The code in Listing 24 instantiates the two buttons and the text area shown in the user interface in Figure 2.
final Button startButton = |
An ActionListener on the Start button
When you start the program running, everything gets initialized, following which the program waits for the user to press the Start button. When the user presses the Start button, the program starts forwarding email messages to the secret email account.
The code in Listing 25 instantiates and registers an ActionListener on the Start button to handle the forwarding of messages. Listing 25 shows the beginning of the actionPerformed method, which is executed when the user presses the Start button.
startButton.addActionListener( |
The objective
The objective of the actionPerformed method is to convert all of the message files in the working folder into email message format and to send them to the secret email account.
Listing 25 starts this process by getting a directory listing of all the files in the working folder.
(This code assumes that the working folder contains only message files. If you store other files in that folder, such as a ReadMe.txt file, you will need to add a filter to the code in Listing 25 to isolate the message files in the directory listing.)Process all the files in the working folder
Listing 26 shows the beginning of a for loop designed to extract each message file from the working folder, convert it to email message format, and send it to the secret email account.
for(int msgCounter = 0; |
Get the message number
My code tags the subject of each forwarded message with the original message number of the message as it appeared on the public email server.
(As I mentioned earlier, you can create and use some other tag if you choose to do so. The only requirement is that the tag must be expressed as a String.)A three-digit string
The code in Listing 27 gets the original message number and formats it as a three-digit string.
String strMsgNumber = |
In order for you to understand the code in Listing 27, I need to give you some background information on the file names assigned to each message when it is written into a file by the program named VirPro01a.
Here is a typical file name for a message file in the working folder:
+OK 38 402fb6da00000098
How is the file name constructed?
This file name is constructed directly from a response received from the email server after sending a UIDL command to the server. I believe that this is a standard response for all POP3 email servers.
The first three characters, +OK, indicate that the command was accepted.
(If the command had not been accepted, the response would have begun with -ERR. For more information on this, see the method named validateOneLine in Listing 41 near the end of the lesson.)The message number
The characters between the two spaces specify the message number assigned to this message on the public email server at the time the command was received.
(As I understand it, this message number will change if messages with lower message numbers are deleted from the server. In other words, any time you access the server to download messages:The unique identifier, UIDL
If you go back and re-examine the code in VirPro01a, you will see that I downloaded all the messages without deleting any messages. Had that program needed to delete messages, I would have downloaded all the messages before deleting any messages to avoid having duplicate message numbers.)
- The message numbers will begin with 1.
- Messages will have sequential numbers.
- There will be no gaps between the sequential message numbers.
The long string of characters following the second space in the file name is a unique ID assigned by the server to that message.
(Again, as I understand it, this unique ID will never be duplicated for another message on that server for the same email account, but may be duplicated for messages on different email accounts on the same server, or may be duplicated by different email servers.)The pathFileName variable
The value of pathFileName in Listing 27 is simply the file name prepended by the path to the file.
Given the form of pathFileName, you should be able to understand how the code in Listing 27 extracts the message number and converts it into a three-digit string containing the message number, such as 001, 063, or 169.
(If I ever have more than 999 messages on the server at any one time, I will have to expand this code to produce a four-digit message number string. I will call that an M1K problem in deference to the Y2K problems of several years ago.)Forward the message to the secret email account
The code in Listing 28 invokes the forwardEmailMsg method (discussed earlier) to format the information in the message file into an email message and to send it to the secret email account.
boolean okToDelete = |
Mark the message for deletion
If the forwardEmailMsg method returns true, the code in Listing 29 adds the pathFileName identifying the message file to a Vector collection referred to by msgToDelete. The contents of this collection will be used later to delete the message from the public email server, and also to move the message file from the working folder to the archive folder.
if(okToDelete){ |
If the forwardEmailMsg method returns false, the pathFileName for that message file is not added to the collection. As a result, the message will not be deleted from the email server, and the message file will not be moved to the archive folder.
(If you don't have WebMail access to your POP3 server, you may need to write a special short program whose purpose is to delete a single malformed message that never gets forwarded, and therefore never gets deleted from the server.)Display information for the user
The code in Listing 29 also displays information in the text area of Figure 2 to keep the user informed as to the success or failure of the attempt to forward the message to the secret email account.
End of the loop
The code in Listing 29 also signals the end of the for loop that controls the processing of all the message files in the working folder.
Enable the Delete button
The code in Listing 30 enables the Delete button and posts a deletion message in the text area of Figure 2.
deleteButton.setEnabled(true); |
Alert the user
The code in Listing 31 produces three audible beeps to alert the user that the message forwarding process is complete, and that it is time to make a decision regarding the deletion of messages from the public email server.
try{ |
An ActionListener on the Delete button
Listing 32 shows the beginning of code that instantiates and registers an ActionListener object on the Delete button shown in Figure 2.
deleteButton.addActionListener( |
The code in Listing 32 also moves the selection point in the text area to the end of its contents in case it has been scrolled to another point.
Connect to the public email server
The code in Listing 33 gets a connection to the public email server in preparation for deleting messages from the server.
int port = 110; //pop3 mail port |
Begin the message deletion process
The code in Listing 34 begins the process of:
- Extracting message identification information from the Vector collection referred to by msgToDelete.
- Deleting the identified messages from the public email server.
- Moving the corresponding message files from the working folder to the archive folder.
for(int cnt = 0; |
In order to delete a message from the email server, that message must be identified by the message number on the server. The code in Listing 34 extracts the message number from the identification information stored in the Vector collection.
This code is essentially the same as code that I discussed in conjunction with Listing 27, so I won't discuss it further. Suffice it to say that this code is executed once for each message identifier contained in the Vector collection referred to by msgToDelete.
How to delete a message from the server
Deletion of a message from the server is accomplished by marking the message for deletion by issuing a DELE command while in the TRANSACTION state. The message is actually deleted later when the client issues a QUIT command to the server causing the server to enter the UPDATE state. If the program aborts prematurely before sending a QUIT command, marked messages are not deleted from the server.
Mark the message for deletion
The message is marked for deletion by executing the statement shown in red in Listing 35.
System.out.println( |
CAUTION
You should not enable this statement until you have thoroughly tested the program on your system and are satisfied that it is behaving properly. If you do, you may lose email messages by deleting them without properly forwarding them to your secret email account.
As long as you don't delete the messages from the server, you can read them using your normal message-reading procedure with your normal email client program.
(If your public email server provides the ability for you to view the messages on the server using WebMail, this is a useful way to monitor everything that is going on while you are testing this program on your system. WebMail normally allows you to view the messages without removing them from the server.)Move the message file
Listing 36 invokes the moveFile method (discussed earlier) to move the message file from the working folder to the archive folder.
moveFile(pathFileName,archivePath); |
Terminate the session
Listing 37 terminates the session with the public email server by issuing a QUIT command, causing previously marked messages to be deleted from the server.
outputStream.println("QUIT"); |
Close the socket and clean things up
The code in Listing 38 closes the socket and displays an informative message on the text area in Figure 2.
try{ |
Configure the GUI
Listing 39 configures the GUI shown in Figure 2 by placing various components on it, setting the size, and making it visible.
add(startButton); |
The method named validateOneLine
The complete program, shown in Listing 41 near the end of the lesson, also contains a utility method named validateOneLine. This method is identical to the method having the same name that I explained in an earlier lesson. I won't repeat that explanation here.
Run the Programs
I encourage you to copy the code from Listing 40 and Listing 41
below. Compile and run the programs. Experiment with them,
improving them as you see fit relative to your specific situation.
(IMPORTANT: Let me caution you again not to enable the DELE code in the program named VirPro01b until you are certain that you actually want to delete messages from the server. Once a message is deleted from the server, there is no way to recover it from the server.)
Summary
This lesson provides two Java programs and an operational scheme for preventing email viruses from contaminating your email data.Preventing email data contamination can be very important, not only with respect to protecting valuable email correspondence, but also with respect to ensuring that you have backups suitable for restoring your disk data when needed.
What's Next?
I have no immediate plans for publishing additional lessons on this topic. However, my long-term plans call for combining this scheme with a SPAM screening scheme for the purpose of protecting against email viruses and blocking SPAM with the same program.Complete Program Listing
Disclaimer of responsibility: If you elect to use these programs you use them at your own risk. Make absolutely certain that you understand what you are doing before you compile and execute the programs. Inappropriate use could result in the loss of email messages. The author of these programs, Richard G. Baldwin, accepts no responsibility for any losses that you may incur as a result of using these programs.
/*File VirPro01a.java Copyright 2004, R.G.Baldwin |
/*File VirPro01b.java |
Copyright 2004, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
About the author
Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-
This article was originally published on March 2, 2004