Security Enlisting Java in the War Against Email Viruses, Part 2, A Much...

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

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("nnMessages 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.

[email protected]

-end-
 

Latest Posts

Related Stories