Java设计防病毒电子邮件措施
副标题#e#
这两个措施的操纵都很简朴。这两个措施叫做VirPro01a和VirPro01b,别离与上面接头的假定的景象中的措施A和措施B对应。
措施VirPro01a
VirPro01a措施被设计为把POP3电子邮件处事器作为民众的电子邮件处事器(奥秘电子邮件帐号的处事器可以是任何范例的,譬喻,它可以是典范的WebMail处事器)。本措施在WinXP下利用SDK 1.4.2测试通过。
实例变量
VirPro01a类的开头界说了一个实例变量列表:
class VirPro01a extends Frame{
String dataPath = "./Messages/";
int numberMsgs = 0;
int msgCounter = 0;
int msgNumber;
String uidl = "";//独一的POP3动静ID
BufferedReader inputStream;
PrintWriter outputStream;
Socket socket;
String pathFileName;
dataPath变量包括对当地事情文件夹的指针,该文件夹是存储期待病毒扫描并转发到奥秘电子邮件帐号的动静的处所。
你大概但愿利用另一个差异的文件夹。假如需要这样做,简朴地提供路径和文件夹名称(作为字符串)。你可以发明,我的事情文件夹叫做Messages,它是用包括措施的类文件的文件夹的相对路径指定的。你也可以利用绝对路径。
剩余的实例变量都是措施用于差异目标的简朴事情变量。
Main要领
下面的main要领确认正确的呼吁行参数数量,并利用这些参数来实例化VirPro01a类的一个工具。
public static void main(String[] args){
if(args.length != 3){
System.out.println("Usage: java VirPro01a "+ "pubServer userName password");
System.exit(0);
}// if竣事
new VirPro01a(args[0],args[1],args[2]);
}// main竣事
结构函数
它的结构函数如下:
VirPro01a(String server,String userName, String password){
int port = 110; //pop3邮件端口
try{
//获得套接字,毗连到特定处事器的特定端口
socket = new Socket(server,port);
//从套接字获得输入流
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//从套接字获得输出流
outputStream = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
//毗连后在呼吁行屏幕上显示从处事器吸收到的动静
String connectMsg = validateOneLine();
System.out.println("Connected to server "+ connectMsg);
//此刻通讯历程处于AUTHORIZATION 状态。向处事器发送用户名和暗码。
//呼吁回收明文、大写的方法发送。呼吁后头带有参数。发送呼吁。
outputStream.println("USER " + userName);
//获得响应,并确认响应是+OK而不是-ERR。
String userResponse = validateOneLine();
//在呼吁行屏幕显示响应
System.out.println("USER " + userResponse);
//向处事器发送暗码
outputStream.println("PASS " + password);
//验证处事器的响应是+OK 。在进程中显示响应。
System.out.println("PASS " + validateOneLine());
}catch(Exception e){e.printStackTrace();}
上面的代码成立了与民众电子邮件处事器的通讯路径。
#p#副标题#e#
WindowListener
下面的代码利用匿名类实例化了并注册了一个WindowListener工具,为页面右上角的“Close”按钮处事。
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
//竣事与处事器的对话
outputStream.println("QUIT");
String quitResponse =validateOneLine();
//在呼吁行屏幕上显示响应
System.out.println("QUIT " + quitResponse);
try{
socket.close();
}catch(Exception ex){ System.out.println("\n" + ex);}
System.exit(0);
}// windowClosing竣事
}// WindowAdapter()竣事
);// addWindowListener竣事
Final型的当地变量
下面的代码声明并初始化告终构函数中的两个当地变量:
final Button startButton =new Button("Start");
final TextArea textArea =new TextArea(20,50);
这两个当地变量包括了图1所示的按钮和文本区域的指针。(请留意,这两个当地变量必需利用final标志,因为它们可以或许被匿名类中界说的代码会见。匿名类或当地类中的代码不能会见非final当地变量。)
注册ActionListener
下面的代码显示了用于实例化和注册按钮的ActionListener工具的匿名类:
startButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try{
//此刻通讯历程处于TRANSACTION状态。检索并生存动静
if(numberMsgs == 0){
outputStream.println("STAT");
String stat = validateOneLine();
//获得动静的数量(字符串)
String numberMsgsStr =stat.substring(4,stat.indexOf(" ",5));
//把字符串转换为整型
numberMsgs = Integer.parseInt(numberMsgsStr);
}// 假如numberMsgs == 0终止
//留意:Msg数量从1而不是0开始。检索并生存每个动静。
//每个动静以新行的句点竣事
msgNumber = msgCounter + 1;
if(msgNumber <= numberMsgs){
//处理惩罚下一个动静。获得并生存来自处事器的动静独一标识,
//验证响应
outputStream.println("UIDL " + msgNumber);
uidl = validateOneLine();
//打开输出文件生存动静。利用UIDL作为文件名
pathFileName = dataPath + uidl;
DataOutputStream dataOut =new DataOutputStream(new FileOutputStream(pathFileName));
//发送RETR呼吁开始动静检索历程
outputStream.println("RETR " + msgNumber);
//验证响应
String retrResponse =validateOneLine();
//从处事器读打动静的第一行
String msgLine =inputStream.readLine();
//继承读打动静直到碰着第一个“.”标记。它标识动静竣事。
while(!(msgLine.equals("."))){
//把数据行写入输出文件并读取下一行。
//在写入输出文件的时候插入新行的字符。
dataOut.writeBytes(msgLine + "\n");
msgLine = inputStream.readLine();
}// while竣事
//封锁输出文件。此刻动静存储在以处事器提供的
//独一ID为文件名的当地文件中。
dataOut.close();
//显示进程
textArea.append(msgNumber + "\n");
//增加动静计数器,为下一个动静作筹备
msgCounter++;
//克制用户为每个新动静按下按钮
Toolkit.getDefaultToolkit().getSystemEventQueue().
postEvent(new ActionEvent(startButton,ActionEvent. ACTION_PERFORMED,"Start/Next"));
}//假如msgNumber <= numberMsgs就终止
else{//msgNumber > numberMsgs
//没有更多动静了。克制 Start/Next 按钮
startButton.setEnabled(false);
//提示用户
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
}// else终止
}// try终止
catch(Exception ex){ ex.printStackTrace();}
}// actionPerformed终止
}// ActionListener终止
);// addActionListener终止
ActionListener工具的目标是下载民众电子邮件处事器上的所有动静,把每个单独的动静放入差异的文件中,并把这些文件存储在事情文件夹中。
设置GUI
下面的代码设置了GUI,它多个组件放在页面上,配置页面的巨细,并使页面可视。
#p#分页标题#e#
add(startButton);
add(textArea);
textArea.setText("");
setLayout(new FlowLayout());
setTitle("Copyright 2004, R.G.Baldwin");
setBounds(274,0,400,400);
//使GUI可视
setVisible(true);
}//结构函数竣事
上面的代码同时表白VirPro01a类的结构函数的竣事。
VirPro01b措施
VirPro01b措施包括大量的与前面措施差异的信息。
前面提到,这是设计用于一起利用的两个措施之一,它们与精采的病毒扫描措施一起防备病毒传染电子邮件收件箱。
这个措施需要在VirPro01a运行之后,病毒检测措施已经确保了VirPro01a的输出不包括病毒(可能包括病毒的文件从事情文件夹中删除了),才气运行。
这个措施把电子邮件动静转发到奥秘的电子邮件帐号。在我的系统中,这个进程相对较慢,利用线缆调制解调器,约莫四秒钟转发一条动静。
这个措施在WinXP下利用SDK 1.4.2测试通过。
forwardEmailMsg要领
我的表明将从该措施中最巨大的部门开始。这个要领叫做forwardEmailMsg。个中的一部门巨大性来自它对付没有正式说明文件的Sun提供的一个类(sun.net.smtp.SmtpClient)的大量依赖。这是发送电子邮件动静的一个很是有用的类,被包括在SDK 1.4.2中。可是,它仿佛没有被包括在SDK 1.4.2文档中,但愿在这个类的文档中找到有用的动静很是坚苦。
文档在哪儿?
我可以或许找到的最好的文档是下面的链接http://swig.stanford.edu/pub/java/javadoc/sun/net/smtp/SmtpClient.html。上面的Web站点对付这个类的操纵描写是:“这个类实现了SMTP客户端。为了发送邮件,你需要成立一个新的SmtpClient,挪用‘to’要领添加目标地,挪用‘from’要领为发送者定名,挪用startMessage返回写入动静(带有RFC733头信息)的流,最后封锁SmtpClient。”除了这些简短的描写之外,险些没有其它有用的信息。可是,它已经提供了至关重要的信息,譬喻要领的名称、参数范例、返回范例等等。
一些告诫
#p#分页标题#e#
假如你在Web上搜索这个类,你将找到大量的利用它的告诫信息,个中主要的是Sun并不支持它。假如你在设计一个需要恒久支持和维护的产物,支持信息大概是涉及关键的。可是,我编写的这个措施只供本身利用以防护电子邮件病毒。因此,我不体贴恒久的支持和维护。这个类容易利用,因此它是个很好的选择。
ReadLines要领
ForwardEmailMsg要领利用了另一个叫做readLines的要领。因此,在表明forwardEmailMsg要领之前我将表明readLines要领。ReadLines要领的开始如下:
private String readLines(String pathFileName,
String firstLine,String lastLine){
该要领的参数
该要领吸收下面三个String(字符串)参数:
· pathFileName
· firstLine
· lastLine
设计该要领的主要目标是让你可以或许从文本文件中提取持续的文本行,从第一行开始的内容到但愿获得的最后一行为止。
ReadLines要领从文本文件中读取和生存文本行,它从firstLine界说的行开始,以lastLine界说的行竣事。假如lastLine为null,数据就一直生存到文件竣事;假如firstLine为null,数据生存为文件中开始的第一行。
来自文件中的文本行生存的方法为:把它们毗连成一个String工具,在每一行的竣事向字符串插入newline(新行标识)。文件的名称和路径由pathFileName指定。
该要领的剩余部门
ReadLines要领剩余的代码如下:
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;
}// if竣事
if(isSave){ strBuf.append(data + "\n");
}// if竣事
if((lastLine != null) && (data.startsWith(lastLine))){
break;//不需要读取更多信息了
}// if竣事
}// while轮回竣事
inDataMsg.close();//封锁文件
}catch(Exception e){e.printStackTrace();}
return new String(strBuf);
}//读取数据行竣事
动静的名目
为了使我设计的readLines越发通用,我打算把它设计为从未处理惩罚的动静中提取文本行,因此看一个动静的例子对你来说大概是有益的。
下图显示了一个为了演示目标而发送给本身的未处理惩罚的简朴的电子邮件动静文本(请留意,我在文本中插入和大量的行脱离符,这样才气显示如下)。
Return-Path: <[email protected]>
Received: from ms-smtp-01-eri0.texas.rr.com
(ms-smtp-01.texas.rr.com [24.93.47.40])
by omnistarhost.com (8.11.6/8.11.6)
with ESMTP id i1G1PeX29829
for <[email protected]>; Sun,
15 Feb 2004 19:25:40 -0600
Received: from DickBaldwin.com
(cs24339-166.austin.rr.com [24.243.39.166])
by ms-smtp-01-eri0.texas.rr.com
(8.12.10/8.12.7) with ESMTP id i1G1JHLc003760
for <[email protected]>;
Sun, 15 Feb 2004 19:19:20 -0600 (CST)
Message-ID: <40301A94.607[email protected]>
Date: Sun, 15 Feb 2004 19:19:16 -0600
From: Richard Baldwin <[email protected]>
Reply-To: [email protected]
User-Agent: Mozilla/5.0 (Windows; U; Windows
NT 5.1; en-US; rv:1.4) Gecko/20030624
Netscape/7.1 (ax)
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: [email protected]
Subject: A test msg to illustrate messagestructure
Content-Type: text/plain;
charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
X-MailScanner-Information: Please
contact the ISP for more information
X-MailScanner: Found to be clean
Status:
This is a test message.
--
Richard G. Baldwin (Dick Baldwin)
Home of Baldwin's on-line Java Tutorials
http://www.DickBaldwin.com
Professor of Computer Information Technology
Austin Community College
(512) 223-4758 or (512) 250-8682
mailto:[email protected]
http://www.austincc.edu/baldwin/
在图1中我利用加亮显示了两行。
主题行和状态行
在forwardEmailMsg要领的代码中主题行将饰演重要的脚色。在措施中,在动静被转发到奥秘的电子邮件帐号之前,动静编号被插入到主题行中。
#p#分页标题#e#
状态行之前的信息都被认为是动静头部信息。状态行后头的部门都被认为是动静主体。假如你在文本编辑器中阅读未处理惩罚的电子邮件动静,你一般留意电子邮件主体中的动静。
返回到forwardEmailMsg要领
private boolean forwardEmailMsg(String recipient,
String smtpServer,String tag, String pathFileName){
ForwardEmailMsg要领输入的参数是:
· recipient(吸收者)——吸收动静的人的电子邮件地点。在例子中它是奥秘电子邮件帐号。它是措施启动时的呼吁行参数。
· smtpServer(smtp处事器)——对你举办身份验证以发送电子邮件动静的smtp处事器的标识。它也是措施启动时的呼吁行参数之一。
· tag(标志)——它是动静被转发到吸收者之前插入主题开始部门的字符串。我利用的是来自民众电子邮件处事器的原始动静编号,你可以改变它。
· pathFileName(文件名和路径)——将转发到奥秘电子邮件帐号的动静的标识。
当地变量
下面的要领声明并初始化了要领后头将利用的当地变量:
StringBuffer message = new StringBuffer("No message found");
SmtpClient结构函数
前面提到的文档提供了类的两个重载的结构函数:
· 一个用于成立未初始化的SMTP客户端。
· 另一个用于成立毗连到特定主机的新SMTP客户端。
try{
SmtpClient smtp =new SmtpClient(smtpServer);
上面的代码利用了第二个结构函数,它实例化一个毗连到用户在呼吁行参数中提供的smtpServer的SmtpClient工具。
from()要领
尽量起面提到的文档没有提高该要领的描写,可是可以直观地推导得出该要领需要吸收发送动静的人的电子邮件地点。
smtp.from(recipient);
它需要一个大概存在的电子邮件地点
在例子中,实际上基础不体贴电子邮件是谁发送的,也就是说它是一个大概存在的电子邮件地点。奥秘电子邮件帐号的客户端措施将从动静头部的From:行中获得动静的发送者。
(可是有须要给from要领通报一个大概存在的电子邮件地点。不然它会发生一个异常。你大概很是奇怪,为什么from要领不执行什么操纵却存在。你通报到from要领的电子邮件地点将显示在动静头部的Return-Path中,图3中有例子。)
由于我知道吸收者的电子邮件地点是大概存在电子邮件地点,我就把吸收者的电子邮件地点作为动静的发送者通报到from要领中。
to()要领
这个要领需要把估量的动静吸收者的电子邮件地点作为参数。代码把吸收者的电子邮件地点通报给to()要领:
smtp.to(recipient);
StartMessage要领
这个要领获得并返回一个PrintStream工具用于成立动静:
PrintStream msg = smtp.startMessage();
上面的代码挪用startMessage要领获得PrintStream工具的指针,并把该指针生存在变量msg中。
获得字符串形式的全部的动静
下面的代码挪用readLines要领获得来自pathFileName指定的文件的全部的动静,并把它转换成一个String工具:
message = new StringBuffer(readLines(pathFileName,null,null));
请留意,上面的代码给readLines通报了两个空(null)参数,指示它利用文件中的所有文本行构建并返回字符串。
把标志插入主题行
下面的代码执行如下操纵:
· 把输入参数tag的值直接地插入主题行,在当前主题之前。
· 把动静从StringBuffer工具转换成String工具,并挪用println要领把它插入输出流。
message = message.insert0(message.indexOf("Subject: ")+9,tag);
msg.println(new String(message));
发送动静
下面的代码挪用SmtpClient工具上的closeServer要领:
//封锁流并发送动静
smtp.closeServer();
return true;
}catch( Exception e ){
System.out.println("\n" + e);
System.out.println("Forwarding email");
Toolkit.getDefaultToolkit().beep();
try{
Thread.currentThread().sleep(300);
}catch(Exception ex){
System.out.println(ex);
}// catch竣事
Toolkit.getDefaultToolkit().beep();
return false;
}// catch竣事
}//end forwardEmailMsg
这段代码会引起动静被发送到吸收者,尽量前面提到的文档中没有明晰地说明。
乐成时返回true
假如上面的代码返回true就表白挪用的要领发送了动静,而且此刻可以从处事器删除该动静,从事情文件夹移动到文档文件夹了。
异常
假如forwardEmailMsg要领中挪用的任何SmtpClient要领发生了异常,它城市被代码中的catch代码块捕获到。
#p#分页标题#e#
Catch代码块输出一些诊断信息、提醒用户并返回False。它表白挪用要领并没有滚动员静,不能从民众电子邮件处事器上删除它,不能移动到文档文件夹中。
从头运行VirPro01b来试图发送动静大概有用,也大概没有用,这依赖于异常的详细种类。假如引起异常的是严重的网络拥塞而导致的超时,那么从头运行措施发送动静是很好的选择。对付其它一些更严重的问题,从头运行大概不会乐成,应该在前面提到的文本编辑器中查抄动静。
MoveFile要领
在进入VirPro01b类的结构函数的细节前我还要接头另一个有用的要领。下面的代码完整地显示了moveFile要领:
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));
}// moveFile要领竣事
输入参数
这个要领吸收两个输入参数:
· PathFileName(文件名和路径)——文件的名称和当前位置。
· ArchivePath(文档路径)——文件的目标地。
这个要领用于把动静文件从事情文件夹移动到文档文件夹。它把文件从pathFileName指定的当前位置移动到archivePath指定的新位置。
假如操纵乐成,File类的reName要领将返回true,不然返回false。譬喻,假如在方针文件夹中已经存在一个同名的文件,操纵将返回false,而且上面的代码将输出一个动静表白移动操纵没有乐成。
VirPro01b类
下面的代码是VirPro01b的开始部门,包罗一些实例变量的声明和初始化。个中一些注释表白了实例变量的利用要领,因此我没有进一步表明它们。
class VirPro01b extends Frame{
//下面是措施启动时保密电子邮件提供的ID它是作为呼吁行参数提供的
String recipient;
//下面是存储期待病毒扫描和转发的动静文件的当地文件夹。
//你可以改变它。
String dataPath = "./Messages/";
//下面是存储扫描后并转发到奥秘电子邮件帐号的动静的当地文件夹。
//从民众电子邮件处事器上删除后它们被自动地移动到这个文件夹。
//你大概需要周期性地排除这个文件夹。
String archivePath = "./Archives/";
//下面是措施用于差异目标的事情变量。
BufferedReader inputStream;
PrintWriter outputStream;
Socket socket;
String pathFileName;
Vector msgToDelete = new Vector();
我要提醒你,你可以通过简朴地改变dataPath和archivePath的初始值来改变事情文件夹和文档文件夹的位置和名称。(在运行措施之前要确保新的文件夹已经成立了。)
Main要领
Main要领如下所示:
public static void main(String[] args){
if(args.length != 5){
System.out.println("Usage: java VirPro01b " + "pubServer userName password " + "secretServer smtpServer");
System.exit(0);
}// if竣事
new VirPro01b(args[0],args[1],args[2], args[3],args[4]);
}// main竣事
Main要领中的代码确保了正确的呼吁行参数的数量,接着利用这些参数实例化VirPro01b了的一个工具。
VirPro01b类的结构函数
结构函数从把奥秘电子邮件地点存储在叫做recipient的实例变量开始,使它可以或许被类中的其它要了解见。其它的输入参数只在结构函数内部利用,因此没有须要把它们作为实例变量生存。
VirPro01b(final String server,final String userName,
final String password,String secretServer,
final String smtpServer){
recipient = secretServer;
可是你必需把它们声明为final的,因为它们要被匿名类界说中的代码会见。
WindowListener工具
下面的代码界说了一个匿名的类,并实例化了该类的一个匿名工具,它实现了WindowListener接口:
this.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}// windowClosing竣事
}// WindowAdapter()竣事
);// addWindowListener竣事
这个WindowListener工具注册在页面上,当用户点击“close”按钮的时候,它引起措施终止。
GUI组件
下面的代码实例化了用户界面中的两个按钮和文本区域:
#p#分页标题#e#
final Button startButton =new Button("Start");
final Button deleteButton = new Button("Delete Msg On Server");
final TextArea textArea =new TextArea(20,50);
同样,这些指针也被声明为final的,因为它们需要被匿名类的工具会见。
“Start”按钮上的ActionListener
当措施开始运行的时候,每个部门都被初始化好了,措施就期待用户点击“Start”按钮了。当用户点击“Start”按钮的时候,措施开始把电子邮件动静转发到奥秘的电子邮件帐号。
下面的代码在“Start”按钮上实例化并注册了一个ActionListener用于处理惩罚动静的转发。代码显示的是actionPerformed要领的前面一部门,该要领在用户点击“Start”按钮的时候执行。
startButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
startButton.setEnabled(false);
File dataDir = new File(dataPath);
String[] dirList = dataDir.list();
上面的代码当纵然“Start”按钮不能利用,以确保该按钮只会被点击一次。
目标
actionPerformed要领的目标是把事情文件夹中的所有动静文件转换为电子邮件动静名目并把它们发送到奥秘的电子邮件帐号。上面的代码通过获得事情文件夹中的所有文件的列表开始这个进程。
(代码假设事情文件夹中只包括动静文件。假如你在该文件夹中存储了其它的文件,譬喻ReadMe.txt文件,你需要给上面的代码添加过滤器以提取目次列表中的动静文件。)
处理惩罚事情目次中的所有文件
下面的代码显示了用于提取事情文件夹中的每个文件,把它转换为电子邮件动静名目,并发送到奥秘的电子邮件帐号的for轮回的开始部门:
for(int msgCounter = 0;
msgCounter < dirList.length;msgCounter++){
String fileName =dirList[msgCounter];
pathFileName = dataPath + fileName;
获得动静的数量
我的代码把每个转发的动静的主题标志上来自民众电子邮件处事器的原始的动静编号(前面提到,你可以成立和利用其它的标志,独一的要求是该标志必需是字符串型的)。
三个数字的字符串
下面的代码获得原始的动静编号并把它名目化为三个数字的字符串:
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;
}// else竣事
文件名中的信息
为了领略上面的代码,我必需给出动静被写入文件时,它的文件名的一些配景信息。下面是一个事情文件夹中的一个典范的文件名:
+OK 38 402fb6da00000098
这个文件名是如何组成的?
这个文件名是给处事器发送UIDL呼吁后,由从处事器上吸收到的响应直接组成的。我相信这是所有POP3电子邮件处事器的尺度响应信息。
前面三个字符是+OK,它表白呼吁被吸收了(假如呼吁没有被吸收,响应将会以-ERR开始。你可以查察完整代码中的validateOneLine要领找到更多的具体信息)。
动静的编号
两个空格之间的字符是民众电子邮件处事器在吸收到呼吁时赋予动静的编号(据我所知,假如从处事器上删除了编号较小的动静,动静的编号将会产生改变,换句话说,你每次会见处事器下载动静时:
· 动静的编号从1开始。
· 动静是有序编号的。
· 顺序的动静编号之间不会有旷地。
假如你转头查察中的VirPro01a代码,你会发明我下载了所有的动静而没有删除任何动静。假如措施要求删除动静,我必需在删除任何动静之前先下载所有的动静,以制止动静编号被反复。)
独一标识符UIDL
文件名中第二个空格之后的长字符串是处事器给动静赋予的一个独一的ID(同样,据我所知,这个独一的ID对付该处事器上的沟通的电子邮件帐号的任何动静是永远不会反复的,可是对付沟通处事器上的差异的电子邮件帐号或差异的电子邮件处事器上的动静是大概反复的)。
PathFileName变量
#p#分页标题#e#
上面的代码中的pathFileName的值仅仅是带有文件路径的文件名。有了pathFileName之后,你就可以或许领略上面的代码如何提打动静编号,并把它转换为包括动静编号的三个数字的字符串,譬喻001、063或169(假如某个时候在处事器上的动静数量多余999个,我就不得不扩展代码以发生四个数字的动静编号字符串。这与几年前的Y2K问题雷同)。
把动静转发到奥秘的电子邮件帐号
下面的代码挪用forwardEmailMsg要领(前面已经接头过了)把动静文件中的信息名目化为电子邮件动静,并把它发送给奥秘的电子邮件帐号:
boolean okToDelete =
forwardEmailMsg(recipient, smtpServer,
"{"+ msgNumberStr +"}",pathFileName);
回首一下forwardEmailMsg要领,假如转发操纵乐成,它就返回true,不然返回false。其返回值存储在代码的okToDelete变量中。
标志可删除的动静
假如forwardEmailMsg要领返回true,下面的代码就把标识动静文件的pathFileName添加到msgToDelete指向的Vector荟萃。该荟萃的内容用于今后从民众电子邮件处事器上删除动静,还用于把动静文件从事情文件夹移动到文档文件夹:
if(okToDelete){
textArea.append("Forwarded " +msgNumberStr + "\n");
msgToDelete.add(pathFileName);
}else{
textArea.append("Failed " +msgNumberStr + "\n");
}// else竣事
}//目次长度上的轮回竣事
不标志的动静
假如forwardEmailMsg返回false,动静文件的pathFileName就不会添加到荟萃中。其功效是该动静不会从电子邮件处事器上删除,动静文件也不会移动到文档文件夹中。
为用户显示信息
上面的代码也在文本区域显示信息,利用户知道动静转发到奥秘的电子邮件帐号的实验是否乐成。
轮回竣事
上面的代码还表白了节制事情文件夹中的所有动静的处理惩罚进程的for轮回的竣事。
激活“Delete”按钮
下面的代码激活“Delete”按钮,并在文本区域宣布一个删除动静:
deleteButton.setEnabled(true);
textArea.append("\nDo you want to "
+ "delete messages from server?\n");
激活“Delete”使得用户可以或许激活注册在该按钮上的ActionListener,用于从民众电子邮件处事器上删除动静,并把动静文件从事情文件夹移动到文档文件夹。
提醒用户
下面的代码发出三声“嘟嘟”提醒用户转发进程完成了,可以抉择是否删除民众电子邮件处事器上的动静了:
try{
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(300);
Toolkit.getDefaultToolkit().beep();
}catch(Exception ex){
ex.printStackTrace();
}// catch竣事
}// actionPerformed竣事
}// ActionListener竣事
);// addActionListener竣事
上面的代码同时表白在“Start”按钮上注册的ActionListener实例的竣事。
“Delete”按钮上的ActionListener
下面的代码显示了实例化和注册图2中的“Delete”按钮上ActionListener工具的代码的开始部门:
deleteButton.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
deleteButton.setEnabled(false);
textArea.append("\n");
上面的代码当即克制了“Delete”按钮,以确保它只会被激活一次。它还把文本区域中的选择点(selection point)移动到文本区域的末端。
毗连到民众电子邮件处事器
下面的代码获得民众电子邮件处事器的毗连用于删除处事器上的动静:
int port = 110; //pop3邮件端口
try{
//获得套接字,毗连到特定处事器的特定端口
socket = new Socket(server,port);
//从套接字获得输入流
inputStream = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
//从套接字获得输出流
outputStream = new PrintWriter(new OutputStreamWriter(
socket.getOutputStream()),true);
//在毗连后头的呼吁行屏幕上显示从处事器吸收到的动静
String connectMsg = validateOneLine();
System.out.println("Connected to server "+ connectMsg);
//此刻通讯历程处于AUTHORIZATION 状态。把用户名和暗码
//发送给处事器。呼吁利用明文、大写方法发送随处事器。
//某些呼吁后头需要随着参数。发送呼吁。
outputStream.println("USER " + userName);
//获得响应,并确认响应是+OK而不是-ERR
String userResponse =validateOneLine();
//在呼吁行屏幕上显示响应信息
System.out.println("USER "+ userResponse);
//向处事器发送暗码
outputStream.println("PASS "+ password);
//验证处事器的响应是否是+OK。显示响应功效
System.out.println("PASS "+ validateOneLine());
}catch(Exception ex){
ex.printStackTrace();
}//catch竣事
从本质上说,上面的代码与VirPro01a措施中的沟通,我就不进一步接头了。
启动动静删除进程
下面的代码启动动静删除进程:
· 从msgToDelete指向的Vector荟萃中提打动静标识信息。
· 从民众电子邮件处事器上删除被标识的动静。
· 把对应的动静文件从民众文件夹移动到文档文件夹。
#p#分页标题#e#
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);
动静编号是必需的
为了从处事器上删除动静,该动静必需由处事器上的动静编号所标识。上面的代码从存储在Vector荟萃中的标识信息中提打动静编号。这段代码对付msgToDelete指向的Vector荟萃中包括的每个动静标识都执行一次。
如何从处事器上删除动静
从处事器上删除动静是通过在TRANSACTION状态时发送DELE呼吁标志供删除的动静来完成的。该动静实际上是在客户端向处事器发送QUIT呼吁,使处事器进入UPDATE状态时才被真正地删除了。假如措施在发送QUIT呼吁前过早地终止了,被标志的动静就不会从处事器上删除。
标志供删除的动静
下面的代码中的通过执行语句(加亮行)标志供删除的动静:
System.out.println("Deletion is temporarily disabled.");
//从处事器上删除被姑且克制了。在彻底相识本身在做什么之前不要启用它。
outputStream.println("DELE " + msgNumber);
//验证并在GUI上显示它
textArea.append("Msg: " + msgNumber + " "
+ validateOneLine()+"\n");
textArea.append("Marked:" + msgNumber + "\n");
留意
在你彻底地测试过这个措施并对它的行为感想满足时才激活这个语句。假如激活了它,你大概由于删除了某些动静,却又没有适内地把它们转发到奥秘的电子邮件帐号而造成某些电子邮件动静的丢失。
只要你不从处事器上删除动静,你就可以利用正常的电子邮件客户端措施阅读它们。
移动动静文件
下面的代码挪用moveFile要领把动静文件从民众文件夹移动到文档文件夹:
moveFile(pathFileName,archivePath);
}//竣事msgToDelete.size()上的轮回
上面的代码还表白节制着msgToDelete所指向的Vector荟萃的内容所标识的所有动静的删除和移动的轮回的竣事。
终止对话
下面的代码民众发送QUIT呼吁终止了与民众电子邮件处事器的对话,它引起被标志的动静从处事器上被删除:
outputStream.println("QUIT");
String quitResponse =validateOneLine();
System.out.println("QUIT " + quitResponse);
如果对QUIT呼吁的响应是+OK,处事器就进入UPDATE模式并删除动静。假如响应是-ERR,处事器就不会进入UPDATE模式,而且动静不会被删除。
封锁套接字并排除信息
下面的代码封锁套接字并在图2的文本区域显示一些有用的动静:
try{
socket.close();
}catch(Exception ex){
ex.printStackTrace();
}// catch竣事
textArea.append("\n\nMessages deleted from server.\n");
}//actionPerformed竣事
}// ActionListener竣事
);// addActionListener竣事
上面的代码同时表白注册到Delete按钮的ActionListener工具的实例化进程的竣事。
设置GUI
下面的代码设置了图2中的GUI,它把多种组件安排在页面上、配置了巨细并使它可视。
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);
//使GUI可视
setVisible(true);
}//结构函数竣事
}// VirPro01b类竣事
上面的代码表白结构函数的竣事以及VirPro01b类的竣事。