September 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Enlisting Java in the War Against Email Viruses, Part 2, A Much Faster Program

  • March 30, 2004
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Java Programming Notes # 2182


Preview

The dangers of viruses in your email

The previous lesson entitled Enlisting Java in the War Against Email Viruses described several of the significant dangers you face when you allow email-borne viruses to get into the email database on your computer.  That discussion ended with the conclusion 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.

Even worse, if an email-borne virus gets loose in your computer, it can do irreparable harm to your computer and many other computers as well.

No virus messages allowed

The best thing is to trap and destroy all email-borne viruses before they have an opportunity to contaminate the email database on your computer.

The purpose of this lesson, and the previous one as well, is to show you one way to accomplish that goal.

A simple and inexpensive scheme

The scheme that I described in the previous lesson is very simple and also very inexpensive.  The resources required consisted of three computer programs and two email accounts, one public and one private.  Two of the computer programs are free, because I am providing them to you.  The third computer program, a virus scanner, is a program that you should already have anyway.

The scheme that I will describe in this lesson is even simpler and less expensive.  This scheme doesn't require a second email account.  Furthermore, the program that I will provide in this lesson will run much faster than the program provided in the previous lesson.

Not as general

However, the program that I will provide in this lesson is not as general as the one provided in the previous lesson.  That program was designed to be used with any POP3 server and any email client program.

The program that I will provide in this lesson is also designed to be used with any POP3 email server, but can only be used with email client programs that employ a common email storage format known as MBOX for local storage of messages.

Many email client programs use MBOX

I have read that many email client programs use MBOX format for local storage of messages.  Most notable among them is the email client in Netscape version 7.0 and later.  (I believe that earlier versions of Netscape also use MBOX, but I have no way to confirm that.)

Unfortunately, I have also read that Microsoft Outlook does not use MBOX format for local storage of messages.  Therefore, this program is probably not compatible with Outlook in its current form.
(Perhaps someone who knows more about Outlook that I do will provide a modified version that is compatible with the message storage format of Outlook.)
Two of the programs are free

As mentioned above, two of the required programs are free, because I am publishing them in this and the previous lesson.  The third required program is a good virus checker program, which you should already have anyway.

The operational scheme

The operational scheme is very simple.  I described it in detail in the previous lesson, and will recap it here with changes pertinent to this version of the program.

For now, let's call the two programs that I will provide program A and program C.

No changes to program A

There have been no significant changes to program A since the publication of the previous lesson.  Program B, as described in the previous lesson has been replaced by program C in this lesson.

Therefore, the first two-thirds of the operational procedure is still the same as described in the previous lesson.

Step 1:  Download messages from your public email server

To begin with, 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.  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 a batch of one hundred messages in just a few seconds, so this process is very fast.)
Step 2:  Scan the message files for viruses

Next you use your favorite virus checker program to scan all of the message files produced by program A, 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 a batch of one hundred messages.

Step 3:  Write an MBOX file containing the clean messages

The next step is to run program C.  This program combines all of the clean messages into a single MBOX file and deposits that file in the directory tree belonging to your email client program.

If you did the virus check (and if you keep your virus checker program up to date), all of these messages should be free of viruses.

A unique file name

The file is given a unique name based on the current date and time, prefixed with an upper case A.  The next time you start your email client program, this file will appear as a folder in your email client display.  That folder will contain all of the messages that were combined into the MBOX file.

A dummy email account may be useful

You can either cause the MBOX file to be stored in the directory tree for your primary email account, or you can establish a dummy email account and store it there if your email client program provides support for multiple accounts.  It really doesn't matter, so long as the name of the MBOX file does not duplicate one of your existing email folder names.
(This is highly unlikely because the file name contains a long string of digits, but it would be even less likely with a dummy email account that doesn't contain any other working folders.)
A very fast process

This process is very fast.  Only a couple of seconds are required on my relatively slow machine to process a batch of approximately one hundred messages.

As soon as this process completes, you can restart your email client program and begin reading the messages contained in the new folder.

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 no more than fifteen or twenty seconds to complete.  This is a small price to pay for assurance that your email database 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 VirPro01c, corresponding respectively to program A and program C in the hypothetical case discussed above.

The program named VirPro01a

As mentioned earlier, the program named VirPro01a has not changed since the publication of the previous lesson.  I discussed this program in detail in the previous lesson, and won't repeat that discussion here.

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 VirPro01c

Once you have a compiled version of VirPro01c on your system, and you have created an archive directory in addition to the working directory, you start the program named VirPro01c by entering the following at the command line prompt.

java VirPro01c pubServer userName password


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
This is the information that you typically enter when setting up a standard email client program.

What is this information used for?

This information makes it possible for the program to delete the corresponding messages from the public email server once they have been written into the MBOX file.
When messages are deleted from the public email server, the corresponding message files are automatically moved from the working folder to the archive folder.
(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 message written into the MBOX file 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 in my email client program folder.

If a message doesn't show up ...

In the unlikely event that a message fails to show up, there is a backup copy in the archive folder.  You can view the backup copy with an ordinary text editor.  I discussed the various ramifications of viewing a raw message with a text editor in the previous lesson.

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 writing them into the MBOX file, just in case I need them for some reason.  You can easily delete this feature if you don't consider it to be important.

The user interface for VirPro01c

Figure 1 shows the simple user interface for VirPro01c.

GUI

Figure 1 User interface for VirPro01c

The user presses the Start button to cause all the messages in the working folder (produced by VirPro01a and scanned by your favorite virus scanner program) to be added to the MBOX file.

The screen shot in Figure 1 was captured at the point where all the messages in the working folder had been written into the MBOX file, and the program was requesting permission to delete those messages from the public email server.

As you can see, once all of the messages in the working directory have been written into the MBOX file, the Delete button is enabled.  This makes it possible for the user to delete the messages from the public email server, and to cause the corresponding message files to be moved from the working folder to the archive folder.

Program Code

Program VirPro01a

As I mentioned earlier, I explained the program named VirPro01a in the previous lesson, and won't repeat that explanation here.

Program VirPro01c

This program contains quite a bit of new information relative to the program named VirPro01b, which I explained in the previous lesson.

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 your email database.

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.  Any files that contain viruses should be removed from the working folder.

This program writes the remaining messages into an MBOX file and deposits that file into the directory structure belonging to your local email client program.

On my system, which is relatively slow, only a few seconds are required to put a batch of about one hundred messages into the MBOX file and to write it into the correct location.

This program was tested using SDK 1.4.2 under WinXP.

The addToMboxStr method

The version of the program discussed in the previous lesson contained a rather complex method named forwardEmailMsg.  One of the major changes to this program (relative to VirPro01b) is the replacement of the forwardEmailMsg method by a new method named addToMboxStr.

As the name implies, the addToMboxStr method is used to add a message to a String containing previously-added messages.  This method is somewhat less complex than the forwardEmailMsg method, but still contains some interesting new material.  I will begin my discussion of the program code with a method that is called by the addToMboxStr method.

The readLines method

The addToMboxStr method calls another method named readLines.  I explained that method in detail in the previous lesson and won't repeat those details here. 

Basically, the method allows you to extract consecutive lines of text from a text file based on the starting content of the first line and the last line that you want to capture.

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.

Now back to the addToMboxStr method

The addToMboxStr method begins in Listing 1

  private StringBuffer addToMboxStr(
StringBuffer mBoxStrBuf,
String tag,
String pathFileName){

Listing 1

The method receives three parameters:
  • mBoxStrBuf:  A StringBuffer object, potentially containing messages previously added, and to which the new message is to be appended.
  • tag:  A String that will be inserted into the Subject line immediately before the body of the Subject line.  My version provides the original message number on the public email server as a tag, but you can modify this to be anything that you find useful.
  • pathFileName:  A string containing the path and file name of the file containing the raw message of interest.
The method returns a reference to an object of type StringBuffer.  This should be the incoming StringBuffer object with the new message appended to it.

Get and save the raw message

Listing 2 invokes the readLines method discussed earlier to get the raw message text as a single String object with new line characters inserted to separate each of the text lines in the original message.

    StringBuffer message = new StringBuffer(
"No message found");
message = new StringBuffer(readLines(
pathFileName,null,null));

Listing 2

This String object is converted to a StringBuffer object in Listing 2 to facilitate the insertion of new material into the message later.

Prepare the message for MBOX compatibility

Preparation of the message for MBOX compatibility requires
the creation of four new header lines and the insertion of those four lines at the beginning of the message. Examples of the four new header lines follow:
  • From - Wed Jan 21 15:59:09 2004
  • X-UIDL: 400ed7770000000b
  • X-Mozilla-Status: 0000
  • X-Mozilla-Status2: 00000000
The first line contains the date and time. The meaning of this line is explained at http://www.qmail.org/man/man5/mbox.html.

The second line contains the UIDL from the email server.

The meaning of the third and fourth lines can be found at various web sites including http://www.eyrich-net.org/mozilla/X-Mozilla-Status.html.

For a new message, the two status values given above are satisfactory.

Insert Mozilla header lines

Listing 3 creates the four special header lines and inserts them at the beginning of the message as required.

    //Get a 24-char date string matching
// the format required by Mozilla.
String theDate = new Date().toString();
theDate = "From - " +
theDate.substring(0,19) +
theDate.substring(23);
//Create the UIDL string.
String xUidl = "X-UIDL:" +
pathFileName.substring(
pathFileName.lastIndexOf(" "));
//Create the two status strings.
String xMozillaStatus =
"X-Mozilla-Status: 0000";
String xMozillaStatus2 =
"X-Mozilla-Status2: 00000000";

//Insert the strings at the beginning of the
// message.
message.insert(0,theDate + "\n" + xUidl
+ "\n" + xMozillaStatus + "\n"
+ xMozillaStatus2 + "\n");

Listing 3

The code in Listing 3 is explained in the comments.

Create a blank line at the end of the message

Listing 4 appends a blank line at the end of the message as required by the MBOX format described in the above reference.

    message.append("\n");

Listing 4

Insert tag in Subject line

Listing 5 inserts the tag in the Subject line of the message at the beginning of the body of the Subject line (following Subject: ).

    message = message.insert(message.indexOf(
"Subject: ")+9,tag);

Listing 5

Append the message to the string and return the result

Listing 6 appends the message to the StringBuffer object that will ultimately be used to create the MBOX-formatted file.

    mBoxStrBuf.append(message);

return mBoxStrBuf;

}//end addToMboxStr

Listing 6

Listing 6 also returns the modified StringBuffer object as required.

Listing 6 also signals the end of the method named addToMboxStr.

The moveFile method

The program shown in Listing 16 near the end of the lesson contains a method named moveFile, which will be invoked later.

This method was not modified in the transition from the program named VirPro01b to the program named VirPro01c.  This method was discussed in detail in the previous lesson and won't be discussed further here.

The validateOneLine method

Similarly, Listing 16 contains a method named validateOneLine, which has not changed relative to the program named
VirPro01b, which was discussed in the previous lesson.  Therefore, I also won't discuss this method in this lesson.

That brings us to a discussion of the main class for this program.

The VirPro01c class

This class is a modification of VirPro01b class discussed in the previous lesson.

Purpose

The purpose of this modified class is to create and to populate an MBOX file directly in the email tree structure on the local disk.  This is an alternative to forwarding the messages to a secret email account via the Internet.

Operational speed and generality

Elimination of the Internet forwarding operation causes this program to run much faster than VirPro01b.

As mentioned earlier, however, this version is less general than the previous version.

While the previous version was compatible with essentially any email client program, this version is compatible only with email client programs that store messages locally in files using a format known commonly as MBOX.

The email client built into Netscape 7.0 and later versions is one email client program that uses MBOX format.

One of a pair of programs

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 your email inbox.  The other program in the pair is the program named VirPro01a, which was discussed in the previous lesson.

VirPro01c should be run after the program named VirPro01a has been run, and after a good virus scanner program has been used to confirm that all the files produced by VirPro01a are free of viruses.  Any files containing viruses should be removed from the system before VirPro01c is run.

Writing and populating the MBOX file

This program writes email messages into an MBOX file, which is located within the directory tree belonging to an email client program.

Only a few seconds are required to process a batch of approximately one hundred messages and to write them into the MBOX file.  This is much faster than the program named VirPro01b, discussed in the previous lesson, can forward messages to a secret email account via the Internet.

Unique MBOX file names

Each time the program is run, a new MBOX file with a unique file name is created and populated with the messages previously created by VirPro01a and scanned with your favorite virus scanner program.

The name of the MBOX file is based on the current date and time prefixed with an upper case A.  This file appears as a folder in your email client program display.

Terminate your email client program

You should terminate your email client program before running VirPro01c.  If you don't, the email client program may not recognize the new email folder corresponding to the MBOX file until the email client program has been stopped and then restarted.

Designed to work with POP3 server

When requested to do so by the user, this program deletes messages from the user's email server.  The messages that are deleted are the same messages that have been written into the MBOX file.

The program is designed to be used with a POP3 email server for deletion of messages. For technical information on POP3, see RFC 1725 at http://www.cis.ohio-state.edu/htbin/rfc/rfc1725.html.

Usage instructions

To start the program, enter the following at the command line:

java VirPro01c pubServer userName password

where the command-line parameters identify:
  • Your public email server
  • Your user name on the public server
  • Your password on the public server
Beginning of the VirPro01c class

Listing 7 shows the beginning of the VirPro01c class along with the declaration and initialization of some instance variables.

class VirPro01c extends Frame{
//The following is the local folder where
// message files are stored awaiting virus
// scanning. You may want to change this to a
// different folder.
String dataPath = "./Messages/";
//The following is the local folder where the
// messages are stored after they have been
// scanned and written into the MBOX file.
// They are automatically moved to this folder
// after being deleted from the public email
// server. You will want to manually empty this
// folder periodically.
String archivePath = "./Archives/";

//The following is the path to the local folder
// where you write files to cause them to be
// treated as email folders.
String emailPath =
"C:/Baldwin/DummyMailAccount/";


//The following are working variables used by
// the program for various purposes.
BufferedReader inputStream;
PrintWriter outputStream;
Socket socket;
String pathFileName;
Vector msgToDelete = new Vector();
StringBuffer mBoxStrBuf = new StringBuffer("");
String newFolder;


Listing 7

With the exception of the variable named emailPath, I am going to let the comments speak for themselves.

The emailPath variable

This is the path
to the local folder where you write files to cause them to be treated as email folders by your email client program.

Not necessarily a valid email account

This doesn't have to be a valid email account.  In other words, if your email client program allows you to set up multiple email accounts, you can set this account up using a dummy POP3 server name, dummy account name, etc.  You will never need to cause your email client program to make use of the POP3 server and account names.

A repository for filing email messages

This account serves simply as a repository for email folders allowing you to file your email messages in an orderly manner.  The messages enter your email database by way of the program named VirPro01c.

Once a new folder has been created and populated by VirPro01c, you should start your email client program and process the messages contained in that folder.
(The email folder name matches the unique file name produced by VirPro01c.)
Processing your messages

Normally you will want to view the subjects and the senders of messages in the new folder and either delete them, or drag them to other folders that you have established for orderly filing of your messages.

Once you have emptied a folder produced by VirPro01c, you should use the facilities of your email client program to delete that folder.  It will be of no further use.

No reason for email client program to support POP3

In the final analysis, there is no reason that you must set your email client program up so that it can actually communicate with your POP3 email server.

When operating according to the methodology described herein, you will always download your email messages using the program named VirPro01a, scan them with your favorite virus scanner program.  Then you will move the clean messages into your email client program's database using the program named VirPro01c.

You will need SMTP capability

Of course, you will need for your email client program to be properly set up for your SMTP server so that you can send email messages.

The main method

The main method for the VirPro01c class is shown in Listing 8.

  public static void main(String[] args){
if(args.length != 3){
System.out.println("Usage: java VirPro01c "
+ "pubServer userName password");
System.exit(0);
}//end if

new VirPro01c(args[0],args[1],args[2]);
}//end main

Listing 8

The code in Listing 8 is completely straightforward and shouldn't require further discussion.

The constructor

The constructor for the class named VirPro01c begins in Listing 9.

  VirPro01c(final String server,
final String userName,
final String password){

newFolder = "A" + new Date().getTime();

Listing 9

The code in Listing 9 creates a name for the MBOX file (newFolder) based on the current date and time down to one millisecond.  Since it is unlikely that this program can be run twice within one millisecond, this file name should be sufficiently unique for practical purposes.

Register a WindowListener and declare component references

The code in Listing 10 is identical to the code discussed in the previous lesson and won't be discussed further here.

    this.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}//end windowClosing
}//end WindowAdapter()
);//end addWindowListener

final Button startButton =
new Button("Start");
final Button deleteButton = new Button(
"Delete Msg On Server");
final TextArea textArea =
new TextArea(20,50);

Listing 10


Register an ActionListener on the startButton

Listing 11 shows the beginning of the code required to register an ActionListener object on the startButton.

    //Register an ActionListener on the
// startButton.
startButton.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent e){
startButton.setEnabled(false);
//Get a directory listing. Make
// certain that dataDir contains only
// message files. Otherwise, you will
// need to upgrade this code to include
// a file name filter.
File dataDir = new File(dataPath);
String[] dirList = dataDir.list();

//Now process the files in the
// directory
for(int msgCounter = 0;
msgCounter < dirList.length;
msgCounter++){
String fileName =
dirList[msgCounter];
pathFileName = dataPath + fileName;

//Create a tag containing the
// original message number from the
// server. This message number will
// be a three-digit string.
String strMsgNumber =
pathFileName.substring(
pathFileName.indexOf(" "),
pathFileName.lastIndexOf(" ")).
trim();
int msgNumber = Integer.parseInt(
strMsgNumber);
String msgNumberStr;
if(msgNumber < 10){
msgNumberStr = "00" + msgNumber;
}else if(msgNumber > 99){
msgNumberStr = "" + msgNumber;
}else{
msgNumberStr = "0" + msgNumber;
}//end else

Listing 11

The code in Listing 11 is the same as code discussed in the previous lesson and won't be discussed further here.

Add the message to the MBOX file

Listing 12 shows the point where this program named VirPro01c departs significantly from the code in the program named VirPro01b discussed in the previous lesson.

            mBoxStrBuf = addToMboxStr(mBoxStrBuf,
"{"+ msgNumberStr +"}",
pathFileName);

Listing 12

Listing 12 invokes the method named mBoxStrBuf to add the message to the MBOX file (instead of forwarding the message to a secret email account as is the case with the program named VirPro01b).

The method named addToMboxStr was discussed earlier in this lesson.
  You can tag the subject with any string that you choose to pass as the second parameter to the addToMboxStr method.  I have chosen to tag the subject with a three-digit message number representing the original message number on the email server.  That makes it easy to confirm that all messages successfully reached the email account.

Indicate that the message has been handled

Listing 13 posts a message on the GUI in Figure 1 showing that the message has been added to the MBOX file.

            textArea.append("Added " +
msgNumberStr + "\n");
msgToDelete.add(pathFileName);
}//end for loop on directory length

Listing 13

More importantly, the code in Listing 13 adds the message path and file name to a collection of messages referred to by msgToDelete.  This is the collection of messages that will be deleted from the email server later when the user presses the Delete button on the GUI in Figure 1.

Listing 13 also signals the end of the loop used to process all of the message files produced earlier by the program named VirPro01a.

Write the MBOX file

Listing 14 writes the String object containing the MBOX-formatted messages into the output file.

          try{
System.out.println("Writing: "
+ emailPath + newFolder);
//Write the updated string into the
// MBOX file (email folder).
DataOutputStream dataOut =
new DataOutputStream(
new FileOutputStream(
emailPath + newFolder));
dataOut.writeBytes(
new String(mBoxStrBuf));
dataOut.close();
}catch(Exception ex){
System.out.println(
"Writing MBOX file");
ex.printStackTrace();
}//end catch

Listing 14

There is nothing complicated about the code in Listing 14, so I won't discuss it further in this lesson.

Complete the definition of the ActionListener

Listing 15 completes the definition of the ActionListener being registered on the Start button in Figure 1.

          deleteButton.setEnabled(true);

textArea.append("\nDo you want to "
+ "delete messages from server?\n");

//Alert the user
try{
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
}catch(Exception ex){
ex.printStackTrace();
}//end catch
}//end actionPerformed
}//end ActionListener
);//end addActionListener

Listing 15

The code in Listing 15 performs the following actions:
  • Enable the Delete button in Figure 1 to make it possible for the user to delete messages from the email server.
  • Post a message in the text area of Figure 1 regarding deletion of messages.
  • Provide an audible alert to the user.
This code is all straightforward and shouldn't require further discussion.

Remaining code

The remaining code in the VirPro01c class is shown in Listing 16 near the end of the lesson.  This code is the same as that discussed in the class named VirPro01b in the previous lesson.  Therefore, I won't discuss it further in this lesson.

The virus message is still on the server

There is one more issue that I need to discuss.  If your virus scanning program detects a virus in a downloaded message file and removes that file from your computer, the file won't be processed by these programs.  That is exactly what you want to happen.  However, because the contaminated file won't be processed locally, it also won't be deleted from the email server.  Therefore, you need some other way to delete the contaminated message from the server.

Move to the head of the line

If all of the other messages in the current batch of messages are successfully deleted from the server, the message containing the virus should move to the position of message number 1 on the server.
(You can confirm that by running these two programs again.  The message containing the virus will be downloaded again, and your virus scanning program should once again identify the file containing the virus.  The file name contains the message number immediately following the +OK in the file name.)
Removing the contaminated message from the server

If you have web mail access to your email server, the easiest thing to do at this point is to access the server using web mail and to delete the message directly from the server.  That is what I do.
(Although my web mail service doesn't expose the message number for each message, it does visually identify the messages that have previously been downloaded but have not yet been deleted.  That makes it easy for me to find and delete the contaminated message from the server.)
What if you don't have web mail?

In this case, you will need a special program designed specifically to delete the contaminated message from the server.

Since the purpose of these lessons is to help you learn to program using Java, I am not going to provide that program for you.  Rather, this is a relatively simple program, so I am going to let you write it for yourself.

If you understand the programs discussed in this and the previous lesson, it shouldn't be a great challenge for you to use the concepts embodied in those programs and to write a new program that connects to your email server and deletes message number 1.
(Before doing that, you should confirm that the contaminated message really does move to the position of message number 1 on your system by cycling through these programs two or three times and observing the message number in the name of the contaminated message file.)

Run the Programs

I encourage you to copy the code from Listing 40 in the previous lesson and Listing 16 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 not to enable the DELE code in the program named VirPro01c 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 a Java program 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

Complete listings of the two programs required to implement this scheme are provided in Listing 40 in the previous lesson and Listing 16 below.

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 VirPro01c.java
Copyright 2004, R.G.Baldwin
Rev 02/22/04

This is a modification of VirPro01b. Its purpose
is to create an MBOX file directly in the email
tree structure rather than to forward the
messages via email. This version runs much
faster than VirPro01b.

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 all files produced
by that program are free of viruses, or that any
files containing viruses have been removed from
the system.

See comments at the beginning of VirPro01a.java
for a description of this pair of programs.

This program writes clean email messages into an
MBOX file, which is located within the directory
tree belonging to an email client program. Only
a few seconds are required to process one hundred
messages and write them into the file.

Each time the program is run, a new MBOX file is
created and populated with the messages
previously created by VirPro01a and scanned with
your favorite virus scanner program. The name
of the file is based on the current date and time
prefixed with an upper case A.

The email client program should be terminated
before this program is run. If not, the email
client program may not recognize the new email
folder corresponding to the MBOX file until the
email client program is stopped and then
restarted.

This program is designed to be used with a email
client program designed to handle files received
from a POP3 email server. For technical
information on POP3,see RFC 1725 at
http://www.cis.ohio-state.edu/htbin/rfc/rfc1725.
html

Usage: Enter the following at the command line:
java VirPro01c pubServer userName password

where the command-line parameters identify:
Your public email server
Your user name on the public server
Your password on the public server

Tested using SDK 1.4.2 under WinXP
************************************************/
import sun.net.smtp.SmtpClient;
import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

class VirPro01c extends Frame{
//The following is the local folder where
// message files are stored awaiting virus
// scanning. You may want to change this to a
// different folder.
String dataPath = "./Messages/";
//The following is the local folder where the
// messages are stored after they have been
// scanned and written into the MBOX file.
// They are automatically moved to this folder
// after being deleted from the public email
// server. You will want to manually empty this
// folder periodically.
String archivePath = "./Archives/";

//The following is the path to the local folder
// where you write files to cause them to be
// treated as email folders. Note that this
// doesn't have to be a valid email account so
// long as the email client program it to be
// valid. In other words, you can create a new
// account in your email client program using
// dummy server names, etc.
String emailPath =
"C:/Baldwin/DummyMailAccount/";

//The following are working variables used by
// the program for various purposes.
BufferedReader inputStream;
PrintWriter outputStream;
Socket socket;
String pathFileName;
Vector msgToDelete = new Vector();
StringBuffer mBoxStrBuf = new StringBuffer("");
String newFolder;

public static void main(String[] args){
if(args.length != 3){
System.out.println("Usage: java VirPro01c "
+ "pubServer userName password");
System.exit(0);
}//end if

new VirPro01c(args[0],args[1],args[2]);
}//end main
//===========================================//

//Constructor
VirPro01c(final String server,
final String userName,
final String password){

newFolder = "A" + new Date().getTime();

//Register a window listener to service
// the close button on the Frame.
this.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}//end windowClosing
}//end WindowAdapter()
);//end addWindowListener

final Button startButton =
new Button("Start");
final Button deleteButton = new Button(
"Delete Msg On Server");
final TextArea textArea =
new TextArea(20,50);

//Register an ActionListener on the
// startButton.
startButton.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent e){
startButton.setEnabled(false);
//Get a directory listing. Make
// certain that dataDir contains only
// message files. Otherwise, you will
// need to upgrade this code to include
// a file name filter.
File dataDir = new File(dataPath);
String[] dirList = dataDir.list();

//Now process the files in the
// directory
for(int msgCounter = 0;
msgCounter < dirList.length;
msgCounter++){
String fileName =
dirList[msgCounter];
pathFileName = dataPath + fileName;

//Create a tag containing the
// original message number from the
// server. This message number will
// be a three-digit string.
String strMsgNumber =
pathFileName.substring(
pathFileName.indexOf(" "),
pathFileName.lastIndexOf(" ")).
trim();
int msgNumber = Integer.parseInt(
strMsgNumber);
String msgNumberStr;
if(msgNumber < 10){
msgNumberStr = "00" + msgNumber;
}else if(msgNumber > 99){
msgNumberStr = "" + msgNumber;
}else{
msgNumberStr = "0" + msgNumber;
}//end else

//Add the message to the MBOX file.
// You can tag the subject with any
// string that you want to pass as
// the second parameter. I will tag
// with the message number as three
// digits. That makes it easy to
// confirm that all messages
// seccessfully reached the email
// account.
mBoxStrBuf = addToMboxStr(mBoxStrBuf,
"{"+ msgNumberStr +"}",
pathFileName);

textArea.append("Added " +
msgNumberStr + "\n");
msgToDelete.add(pathFileName);
}//end for loop on directory length

try{
System.out.println("Writing: "
+ emailPath + newFolder);
//Write the updated string into the
// MBOX file (email folder).
DataOutputStream dataOut =
new DataOutputStream(
new FileOutputStream(
emailPath + newFolder));
dataOut.writeBytes(
new String(mBoxStrBuf));
dataOut.close();
}catch(Exception ex){
System.out.println(
"Writing MBOX file");
ex.printStackTrace();
}//end catch

//Make it possible for the user to
// delete all messages that were
// successfully written into the MBOX
// file.
deleteButton.setEnabled(true);
textArea.append("\nDo you want to "
+ "delete messages from server?\n");

//Alert the user
try{
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
}catch(Exception ex){
ex.printStackTrace();
}//end catch
}//end actionPerformed
}//end ActionListener
);//end addActionListener

//Register an action listener on the delete
// button
deleteButton.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent e){
deleteButton.setEnabled(false);
textArea.append("\n");

//Get connected to the email server
int port = 110; //pop3 mail port
try{
//Get a socket, connected to the
// specified server on the specified
// port.
socket = new Socket(server,port);

//Get an input stream from the socket
inputStream = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));

//Get an output stream to the socket.
outputStream = new PrintWriter(
new OutputStreamWriter(
socket.getOutputStream()),
true);

//Display the msg received from the
// server on the command-line screen
// immediately following connection.
String connectMsg =
validateOneLine();
System.out.println(
"Connected to server "
+ connectMsg);

//The communication process is now in
// the AUTHORIZATION state. Send the
// user name and password to the
// server.
//Commands are sent in plain text,
// upper case to the server. Some
// commands require an argument
// following the command, as is the
// case with USER.
//Send the command.
outputStream.println("USER "
+ userName);
//Get response and confirm that the
// response was +OK and was not -ERR.
String userResponse =
validateOneLine();
//Display the response on the
// command-line screen.
System.out.println("USER "
+ userResponse);
//Send the password to the server
outputStream.println("PASS "
+ password);
//Validate the server's response as
// +OK. Display the response in the
// process.
System.out.println("PASS "
+ validateOneLine());
}catch(Exception ex){
ex.printStackTrace();
}//end catch

//Delete the collection of messages in
// msgToDelete from the public email
// server. Also transfer the local
// copies of the message files to the
// archive folder.
for(int cnt = 0;
cnt < msgToDelete.size();cnt++){
pathFileName =
(String)msgToDelete.elementAt(cnt);
String strMsgNumber =
pathFileName.substring(
pathFileName.indexOf(" "),
pathFileName.lastIndexOf(" ")).
trim();
int msgNumber = Integer.parseInt(
strMsgNumber);

//Deletion of a message from the
// server is accomplished by marking
// the message for deletion while in
// the TRANSACTION state. The
// message is actually deleted when
// the client sends 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.
System.out.println(
"Deletion is temporarily disabled.");
/*Deletion from the server temporarily disabled.
*Do not enable this deletion code until you
* understand exactly what you are doing.
outputStream.println(
"DELE " + msgNumber);


//Validate the response and display
// it on the GUI.
textArea.append(
"Msg: " + msgNumber + " "
+ validateOneLine()+"\n");
textArea.append(
"Marked:" + msgNumber + "\n");
*/

//Now move the file that has been
// processed and deleted from the
// server to the archive folder
// on the local disk.
moveFile(pathFileName,archivePath);

}//end for loop on msgToDelete.size()

//Terminate the session with the
// server causing the messages to
// actually be deleted from the server.
outputStream.println("QUIT");
String quitResponse =
validateOneLine();
//Display the response on the
// command-line screen.
System.out.println(
"QUIT " + quitResponse);

//Server is now in the UPDATE mode.
// It will delete all files marked
// with the DELE command earlier.
//Close the socket
try{
socket.close();
}catch(Exception ex){
ex.printStackTrace();
}//end catch

textArea.append("\n\nMessages deleted "
+ "from server.\n");
}//end actionPerformed
}//end ActionListener
);//end addActionListener

//Configure the GUI by placing the
// various components on it, setting the size
// and making it visible.
add(startButton);
add(deleteButton);
deleteButton.setEnabled(false);
add(textArea);
textArea.setText("");
setLayout(new FlowLayout());

setTitle("Copyright 2004, R.G.Baldwin");
setBounds(274,0,400,400);
//Make the GUI visible.
setVisible(true);
}//end constructor
//===========================================//

//Validate a one-line response.
//The purpose of this method is to confirm that
// the server returned +OK and not -ERR to the
// previous command.
//If +OK, the method returns the string
// returned by the server.
//If -ERR, the method displays the string
// returned by the server and terminates the
// session.
private String validateOneLine(){
try{
String response = inputStream.readLine();
if(response.startsWith("+OK")){
return response;
}else{
System.out.println(response);
//Terminate the session.
outputStream.println("QUIT");
socket.close();
System.out.println(
"Premature QUIT on -ERR");
System.exit(0);
}//end else
}catch(IOException e){
System.out.println("\n" + e);
}//end catch
//The following return statement is requied
// to satisfy the compiler.
return "Make compiler happy";
}//end validateOneLine()
//===========================================//

//Method moves a file from its current location
// specified by pathFileName to a new location
// specified by archivePath.
private void moveFile(String pathFileName,
String archivePath){
String fileName = pathFileName.substring(
pathFileName.lastIndexOf('/') + 1);
String archivePathFileName =
archivePath + fileName;

boolean moved =
new File(pathFileName).renameTo(
new File(archivePathFileName));

if(!moved)System.out.println(
"Unable to move " + new File(pathFileName)
+ "\nto " + new File(archivePathFileName));
}//end moveFile method
//===========================================//

//This method reads and saves lines of data
// from a file starting with the line that
// startsWith firstLine and ending with the
// line that startsWith 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 data from the file are saved by
// concatenating them into a single string with
// a newline inserted into the string at the
// end of each line.
//The name and path to the file is given by
// pathFileName.
private String readLines(String pathFileName,
String firstLine,String lastLine){
StringBuffer strBuf = new StringBuffer();
try{
BufferedReader inDataMsg
= new BufferedReader(new FileReader(
pathFileName));

String data;
boolean isSave = false;
while((data = inDataMsg.readLine())
!= null){

if(((firstLine == null) ||
(data.startsWith(firstLine))) &&
(isSave == false)){
isSave = true;
}//end if

if(isSave){
strBuf.append(data + "\n");
}//end if

if((lastLine != null) &&
(data.startsWith(lastLine))){
break;//no need to read any more
}//end if

}//end while loop
inDataMsg.close();//Close file
}catch(Exception e){e.printStackTrace();}
return new String(strBuf);
}//end readLines
//===========================================//
private StringBuffer addToMboxStr(
StringBuffer mBoxStrBuf,
String tag,
String pathFileName){

StringBuffer message = new StringBuffer(
"No message found");
message = new StringBuffer(readLines(
pathFileName,null,null));

//Prepare the message for appending to the
// end of the MBOX string. This requires
// the creation of four new header lines
// and the prepending of those four lines
// onto the message. Examples of those
// four new header lines follow:

//From - Wed Jan 21 15:59:09 2004
//X-UIDL: 400ed7770000000b
//X-Mozilla-Status: 0000
//X-Mozilla-Status2: 00000000

// The first line contains the date and
// time. The second line contains the UIDL
// from the email server. The meaning of
// the third and fourth lines can be found
// at various web sites including
// http://www.eyrich-net.org/mozilla/
// X-Mozilla-Status.html?en
// For a new message, the status values
// given above are satisfactory.

//Create Mozilla header lines and insert
// them at the beginning of the message.
// First get a 24-char date string matching
// the format required by Mozilla.
String theDate = new Date().toString();
theDate = "From - " +
theDate.substring(0,19) +
theDate.substring(23);
//Create the UIDL string.
String xUidl = "X-UIDL:" +
pathFileName.substring(
pathFileName.lastIndexOf(" "));
//Create the two status strings.
String xMozillaStatus =
"X-Mozilla-Status: 0000";
String xMozillaStatus2 =
"X-Mozilla-Status2: 00000000";

message.insert(0,theDate + "\n" + xUidl
+ "\n" + xMozillaStatus + "\n"
+ xMozillaStatus2 + "\n");
//Append a new line at the end of the
// message.
message.append("\n");
//Insert tag in subject line
message = message.insert(message.indexOf(
"Subject: ")+9,tag);

//Append this message at the end of the
// string that will be used to create the
// MBOX file.
mBoxStrBuf.append(message);

return mBoxStrBuf;

}//end addToMboxStr
//===========================================//

}//end class VirPro01c

Listing 16


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.

Baldwin@DickBaldwin.com

-end-
 








Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel