Trình POP3 Server gồm hai phần, phần POPServer chịu trách nhiệm mở socket
và lắng nghe kết nối từ trình khách gởi lên theo cổng 110 (cổng mặc định của giao
thức POP3). Khi nhận được kết nối, POPServer yêu cầu lớp PÔPCnnection phân tích
các lệnh của giao thức POP3 và gởi mail về cho trình khách. Lớp POP3 được cài đặt như sau:
POPServer.java
import java.net.*; import java.util.*;
public class POPServer extends Thread { public Vector connections;
public Boolean stopRequested; protected ServerSocket listenSocket; public POPServer() throws Exception {
int port = 0;
String portString = null;
// Lấy só hiệu cổng từ file cấu hình try {
portString = Server.properties.getProperty("pop.port"); port = Integer.parseInt(portString);
} catch (NumberFormatException e) {
throw new Exception("Invalid 'pop.port' - " + portString); }
// Lắng nghe trên socket sự kết nối từ trình khách listenSocket = new ServerSocket(port);
// Tạo mảng chứa danh sách các kết nối
}
public void removeConnection(POPConnection connection) { }
/**
* Xử lý kết nối
*/
public void run() {
// Lặp vô tận cho đến khi có yêu cầu dừng
stopRequested = new Boolean(false); while (true) {
synchronized (stopRequested) {
if (stopRequested.booleanValue()) break;
}
// Chấp nhận kết nối do trình khách gởi lên try {
Socket s = listenSocket.accept();
//Yêu cầu lớp POPConnection xử lý giao thức phục vụ trình khách POPConnection connection = new POPConnection(s, this);
connection.setDaemon(true); connection.start(); } catch (IOException e) { e.printStackTrace(); break; } } // Đóng kết nối try { listenSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
Lớp POPConnection.java chịu trách nhiệm chính trong việc xử lý các lệnh của
giao thức POP3. Lớp POPConnection được cài đặt như sau :
POPConnection.java
import java.io.*; import java.net.*; import java.util.*;
public class POPConnection extends Thread { protected static final int ENTER_USER = 0;
protected static final int ENTER_PASSWORD = 1; protected static final int TRANSACTION = 2; protected static final int UPDATE = 3;
protected POPServer server; protected Socket socket; protected BufferedReader in; protected PrintStream out;
protected boolean stopRequested; protected int state;
protected String userName; protected User user;
protected Vector messages = null;
public POPConnection(Socket socket, POPServer server) { super();
this.socket = socket; this.server = server; }
protected void close() { try {
socket.close(); } catch (Exception e) {
System.err.println("Exception trying to close POPConnection socket!"); e.printStackTrace(System.err);
} }
// Đếm số mail có trong hộp thư
protected int countMessages() { if (messages == null)
return 0;
Enumeration enum = messages.elements(); int count = 0;
while (enum.hasMoreElements()) {
Message message = (Message)enum.nextElement(); if (!message.isDeleted()) count++; } return count; } /**
* Lấy nội dung mail dựa vào số thứ tự của mail lưu trong hộp thư
protected Message getMessage(int number) { if (number <= 0 || number > messages.size())
return null;
Message message = (Message)messages.elementAt(number - 1); if (message.isDeleted())
return null; return message; }
protected Message getMessage(String messageNumber) { int number; try { number = Integer.parseInt(messageNumber); } catch (NumberFormatException e) { return null; } return getMessage(number); }
protected long getMessagesSize() { if (messages == null)
return 0;
Enumeration enum = messages.elements(); long size = 0;
while (enum.hasMoreElements()) {
Message message = (Message)enum.nextElement(); if (!message.isDeleted())
size += message.getSize(); }
return size; }
protected void processDELE(StringTokenizer arguments) { if (!arguments.hasMoreTokens()) {
out.println("-ERR must supply message number"); } else {
Message message = getMessage(arguments.nextToken()); if (message == null) {
out.println("-ERR no such message"); } message.setDeleted(true); out.println("+OK"); } } /**
* Xử lý lệnh PASS kiểm tra password
protected void processEnterPassword(String command, StringTokenizer arguments) {
if (command.equalsIgnoreCase("QUIT")) { stopRequested = true;
out.println("+OK Signing off");
} else if (command.equalsIgnoreCase("PASS")) { if (!arguments.hasMoreTokens()) {
out.println("-ERR must supply password"); return;
}
String password = arguments.nextToken(); if (arguments.hasMoreTokens()) {
out.println("-ERR only one argument to PASS, your password"); return;
}
// Kiểm tra quyền đăng nhập
user = Server.storage.login(userName, password); if (user == null) {
out.println("-ERR invalid user or password"); state = ENTER_USER;
} else {
// user đã đăng nhập – trả về danh sách các mail có trong hộp thư
messages = Server.storage.getMessages(user);
state = TRANSACTION; }
} else {
out.println("-ERR Only use PASS or QUIT commands"); }
}
/**
* Xử lý lệnh USER
*/
protected void processEnterUser(String command, StringTokenizer arguments) {
if (command.equalsIgnoreCase("QUIT")) { stopRequested = true;
out.println("+OK Signing off"); return;
}
if (command.equalsIgnoreCase("USER")) { if (!arguments.hasMoreTokens()) {
out.println("-ERR must supply user name"); return;
}
if (arguments.hasMoreTokens()) {
out.println("-ERR only one argument to USER, the user name"); return;
}
state = ENTER_PASSWORD;
out.println("+OK use PASS command to send password"); return;
}
out.println("-ERR Only use USER or QUIT commands"); }
/**
* Xử lý lệnh LIST
*/
protected void processLIST(StringTokenizer arguments) {
if (!arguments.hasMoreTokens()) {
out.println("+OK " + countMessages() + " " + getMessagesSize()); for (int i = 1; i <= messages.size(); i++) {
Message message = getMessage(i); if (message != null) {
out.println(i + " " + message.getSize()); }
}
} else {
String messageNumber = arguments.nextToken(); Message message = getMessage(messageNumber); if (message == null) {
out.println("-ERR no such message"); } else {
out.println("+OK " + messageNumber + " " + message.getSize()); }
} }
/**
* Xử lý lệnh NOOP – Lệnh NOOP của POP3 không làm gì cả, mục đích chỉ để trình khách xem kết nối còn hiệu lực hay không
*/
protected void processNOOP(StringTokenizer arguments) { out.println("+OK");
}
/**
* Xử lý lệnh QUIT
*/
protected void processQUIT(StringTokenizer arguments) { Enumeration enum = messages.elements();
while (enum.hasMoreElements()) {
Message message = (Message)enum.nextElement(); if (message.isDeleted()) {
Server.storage.deleteMessage(message); }
}
out.println("+OK Goodbye, " + user.getName()); stopRequested = true;
} /**
* Xử lý lệnh RETR trả về nội dung mail
*/
protected void processRETR(StringTokenizer arguments) { if (!arguments.hasMoreTokens()) {
out.println("-ERR message number required, RETR 1"); } else {
String messageNumber = arguments.nextToken(); Message message = getMessage(messageNumber); if (message == null) {
out.println("-ERR no such message"); return;
out.println("+OK " + message.getSize() + " octets");
// Đọc dữ liệu mail
StringBuffer buffer = Server.storage.getMessageData(message);
BufferedReader reader = new BufferedReader(new
StringReader(buffer.toString()));
// Đọc từng dòng boolean done = false; try {
while (reader.ready() && (!done)) {
String line = reader.readLine(); if (line == null) break; // Dấu chấm kết thúc if (line.length() >= 1) { if (line.substring(0, 1).equals(".")) line = "." + line; } // Gửi dữ liệu về trình khách out.println(line); }
} catch (IOException e) { System.err.println("POPConnection.processRETR()"); e.printStackTrace(System.err); } try { reader.close(); } catch (IOException e) { System.err.println("POPConnection.processRETR() - reader.close()"); e.printStackTrace(System.err); } out.println("."); } } /** * Xử lý lệnh RSET */
protected void processRSET(StringTokenizer arguments) { Enumeration enum = messages.elements();
while (enum.hasMoreElements()) {
Message message = (Message)enum.nextElement(); if (message.isDeleted())
message.setDeleted(false); }
out.println("+OK"); }
/**
* Xử lý lệnh STAT
*/
protected void processSTAT(StringTokenizer arguments) {
out.println("+OK " + countMessages() + " " + getMessagesSize()); }
/**
* Xử lý lệnh TOP – trả về trình khách các mail header */
protected void processTOP(StringTokenizer arguments) { if (!arguments.hasMoreTokens()) {
out.println("-ERR syntax: TOP <msg> <lines>"); return;
}
String messageNumber = arguments.nextToken();
if (!arguments.hasMoreTokens()) {
out.println("-ERR syntax: TOP <msg> <lines>"); return;
}
int lines = 0; try {
lines = Integer.parseInt(arguments.nextToken()); } catch (NumberFormatException e) {
out.println("-ERR bad number of lines"); return;
}
Message message = getMessage(messageNumber); if (message == null) {
out.println("-ERR no such message"); return;
}
out.println("+OK " + message.getSize() + " octets");
StringBuffer buffer = Server.storage.getMessageData(message);
BufferedReader reader = new BufferedReader(new
StringReader(buffer.toString()));
boolean done = false; boolean inBody = false; int count = 0;
try {
String line = reader.readLine(); if (line == null) break; if (line.length() >= 1) { if (line.substring(0, 1).equals(".")) line = "." + line; } else { inBody = true; } if (inBody) { count++; } out.println(line); } } catch (IOException e) { System.err.println("POPConnection.processTOP()"); e.printStackTrace(System.err); } try { reader.close();
} catch (IOException e) { System.err.println("POPConnection.processTOP() - reader.close()"); e.printStackTrace(System.err); } out.println("."); } /**
* Xử lý các lệnh của giao thức POP3
*/
protected void processTransaction(String command, StringTokenizer
arguments) { if (command.equalsIgnoreCase("STAT")) { processSTAT(arguments); } else if (command.equalsIgnoreCase("LIST")) { processLIST(arguments); } else if (command.equalsIgnoreCase("RETR")) { processRETR(arguments); } else if (command.equalsIgnoreCase("DELE")) { processDELE(arguments); } else if (command.equalsIgnoreCase("NOOP")) { processTOP(arguments); } else if (command.equalsIgnoreCase("TOP")) { processTOP(arguments); } else if (command.equalsIgnoreCase("UIDL")) {
processUIDL(arguments); } else if (command.equalsIgnoreCase("RSET")) { processRSET(arguments); } else if (command.equalsIgnoreCase("QUIT")) { processQUIT(arguments); } else {
out.println("-ERR Unknown command " + command); }
}
protected void processUIDL(StringTokenizer arguments) { if (!arguments.hasMoreTokens()) {
out.println("+OK " + countMessages() + " " + getMessagesSize()); for (int i = 1; i <= messages.size(); i++) {
Message message = getMessage(i); if (message != null) { out.println(i + " " + message.getMessageId()); } } out.println("."); } else {
String messageNumber = arguments.nextToken(); Message message = getMessage(messageNumber); if (message == null) {
out.println("-ERR no such message"); } else {
out.println("+OK " + messageNumber + " " + message.getMessageId()); }
} }
/**
* Nhận kết nối và các lệnh POP3 gửi lên từ trình khách */
public void run() { try {
in = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
out = new PrintStream(socket.getOutputStream()); } catch (IOException e) { e.printStackTrace(System.err); close(); return; } if (server == null) {
System.err.println("SERVER NOT SET!!!"); return;
}
state = ENTER_USER;
out.println("+OK POP3 " + Server.getAddress()); while (!stopRequested) {
try {
String line = in.readLine(); if (line == null)
break;
StringTokenizer tokenizer = new StringTokenizer(line); String command = "";
if (tokenizer.hasMoreTokens())
command = tokenizer.nextToken();
// Xử lý lệnh tuỳ theo trạng thái đăng nhập của user
switch (state) { case ENTER_USER: processEnterUser(command, tokenizer); break; case ENTER_PASSWORD: processEnterPassword(command, tokenizer); break; case TRANSACTION: processTransaction(command, tokenizer);
break; default:
out.println("-ERR invalid state! "); System.err.println("Invalid State in POPConnection.run()");
stopRequested = true; break; } } catch (Exception e) { e.printStackTrace(System.err); stopRequested = true; } } // Đóng kết nối close(); server.removeConnection(this); }
public void setServer(POPServer server) {} }
2.3.CÀI ĐẶT MAILCLIENT
Phần MailClient được thiết kế dưới dạng Web dùng Java Server Page nên được
gọi là một WebMail. Trang Web và quá trình sử dụng mailclient có thể được hình
dung qua sơ đồ và đặc tả đưới đây
HomePage
Đăng Ký Thành Viên
Login Help
Menumail
Inbox AddressBook Option
Add Edit Review
Inf
Change
Password Hình cấu trúc Website
1.Đăng nhập hệ thống :
Lần đầu tiên sử dụng CT để gửi nhận mail, chúng ta phải đăng ký một account
mới cho riêng mình, nghĩa là chúng ta phải có một username và password riêng cho mình nhằm phân biệt những người sử dụng email khác nhau và bảo mật thư của từng người.
_ Đăng nhập username và password trước khi vào hệ thống . Nếu là “member”: bạn có thể sử dụng CT gửi /nhận thư . Nếu là “guest”: bạn phải Đăng ký thành viên
2.Đăng ký thành viên :
Cho lần đầu tiên bạn đăng nhập vào hệ thống , ghi các thông tin cá nhân,
username và password của bạn.
3.Các loại Address Book . Điều chỉnh thông tin trong Personal Address Book :
(User có quyền T, X, S addressbook của mình)
Các thông tin về địa chỉ mail của các Client được lưu trữ trong các sổ địa chỉ.
Mỗi người sử dụng mail thường có một sổ địa chỉ cá nhân (Personal Address Book - PAB) của riêng mình và được lưu trữ trong ổ đĩa cục bộ .
Các thông tin cần thiết khi thêm một địa chỉ E-mail vào PAB:
_ E-mail Addressđịa chỉ E-mail chính xác của người cần thêm vào.
Ngoài ra, chúng ta có thể thêm vào những địa chỉ email khác, số phone, mobile và địa chỉ nhà riêng
4.Review Account Information:
_ User xem lai thông tin cá nhân đã đăng nhập và AddressBook của mình. _ Có thể thay đổi Password (changepassword.asp) khi bạn muốn đặt lại một
password mới cho mình.
5.Thay đổi Pass :
_ Old Password:nhập lại pass hiện tại.
_ New password: nhập pass mới. Bạn có thể sử dụng các ký tự chữ, số và cả hệ
thống chấm câu, nhưng không thể sử dụng khoảng trắng.
_ Nhập lại password một lần nữa. Nếu so trùng, việc thay đổi password xem như
6.Kiểm tra thư:
Vùng nội dung các Folder sẽ xuất hiện tiêu đề các thư trong folder đó. Các thư chưa được đọc thường được trình bày khác với thư đã được đọc. Thông thường phần tiêu đềthư gồm các nội dung như sau:
_ From: Tên người gửi, nội dung xuất hiện ở đây không phải là địa chỉ e-mail của người gửi mà là họ tên của người gửi.
_ Subject : Chủ đề của lá thư . Khi gửi thư, ngưòi gửi thường ghi một nội dung
ngắn vào vùng subject để người nhận biết được mục đích tổng quát của lá thư trước
khi quyết định có đọc thư hay không.
_ Date : Ngày giờ nhận thư
_ Size: Kích thước lá thư (thường tính bằng KB)
7.Đọc thư :
Tất cả thư của bạn được liệt kê trong một bảng trong Inbox với mỗi hàng là một thư. Để xem nội dung thư cần click vào vùng tiêu đề của thư. Trong vùng nội dung
INBOX
CheckMail Upload File Compose
Read Reply Delete
DownLoad
Send Error
thư, các thông tin của ngưòi gửi sẽ được thể hiện cùng nội dung lá thư . Các thông tin người gửi bao gồm: tên người gửi, thời điểm gửi, tên người nhận
Muốn đọc email nào, click vào cột Fromtương ứng. Sau khi đọc xong, để đọc thư
khác, click vào Inbox hay click vào nút Back của Internet Explorer.
_ Sau khi đọc xong thư ,Delete nếu muốn xóa thư.
_ Reply nếu muốn trả lời thư
_ Download attach file nếu thư có gửi file kèm theo .
8.Viết email trong WebMail: Chúng ta có hai trường hợp:
Nếu bạn đang đọc một thư nào đó, bạn muốn trả lời thư đóthì click vào nút
Reply phía trên.
Nếu bạn muốn gửi thư trực tiếp, click vào nút Compose.
Khi muốn gửi thư cho một người đã có địa chỉ trong một AddressBook, đầu
tiên phải chuẩn bị nội dung thư để gửi. Phần tiêu đề của một thư cần gửi bao gồm các
thông tin sau:
_ To: Địa chỉ email mà bạn muốn gửi tới.
_ Subject: một đoạn text ngắn cho biết mục đích của nội dung thư cần gửi. Đoạn text này giúp cho người đọc thư quyết định có nên xem nội dung của thư hay
không.
_ Attachments gởi kèm tập tin cho nguười nhận.
_ Nội dung soạn trong comment
_ Sau khi soạn thảo nội dung thư xong, nhấn nút Send để thư được cất vào Outbox. Nghĩa là, thư không được truyền đi ngay, do đó chúng ta có thể soạn thảo
Sinh viên thực hiện Nguyễn Xuân Thanh Trang
Khi thư đã đưa vào Outbox, mọi chỉnh sửa tiếp theo thường làm thư không gửi đi được nữa. Trường hợp này cần phải soạn thảo một lá thư khác để gửi đi và xóa bỏ lá thư cũ.
9.Gửi kèm file theo Mail (attach file)
Trong một số trường hợp cần đưa thêm toàn bộ nội dung một tập tin đang có
sẵn trên đĩa cục bộ vào thư để gửi đến ngưòi nhận. Công việc này được gọi là Attach
file vào thư.
Cần chú ý rằng việc attach một tập tin vào mail cần phải được thực hiện đồng bộ
giữa người gửi , người nhận và đường truyền thư.Nếu không có sự đồng bộ, nội dung
của tập tin được attach có người nhận không đọc được. Lý do của việc này là do nội
dung của tập tin được attach sẽ được mã hoá theo UUENCODE hay theo MIME (Multipurpose Internet Mail Extensions).
Thông thường để giảm thời gian truyền thư, các tập tin cần attach vào thư sẽ được nén trước khi thực hiện thao tác attach. Cách nén thông dụng là ZIP.
Các tập tin được gửi kèm có thể lưu thành một tập tin riêng trong điã cục bộ của người sử dụng. Thông thường dung lượng tập tin gửi kèm không nên quá 1MB, nếu
lớn hơn ta cần tách ra gửi nó trong nhiều thư.
10. Download / Upload file
Một số giao diện
Menu chính
TÀI LIỆU THAM KHẢO
Phân tích, thiết kế và cài đặt hệ thống thông tin quản lý - Hiệu đính: GS. Bạch Hưng Khang Cơ sở dữ liệu quan hệ - Lê Tấn Vương
System Administrator for Microsoft SQL Serever 7.0 workbook Microsoft SQL Server 7.0 Database Implementation Training Kit Microsoft SQL Server hoạch định và xây dựng cơ sở dữ liệu cao cấp Allaire JRUN Developer Documentation
Enterprise JavaBeans – Tom Valesky
HTML by Example – Todd Stauffer
Special Edition Using HTML 4 – Jerry Honeycutt Special Edition Using JavaScript – Mark C. Reynolds Java by Example – Clayton Walnum
Lập trình Java thế nào? – Hoàng Ngọc Giao
Java lập trình mạng – Nguyễn Phương Lan, Hoàng Đức Hải Các tài liệu về JSP/EJB tại website: http://java.sun.com