PopClean.java Source code

Java tutorial

Introduction

Here is the source code for PopClean.java

Source

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
//package je3.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A simple utility program for deleting messages from a POP3 mailbox based on
 * message size and Subject line. Don't run this program unless you understand
 * what it is doing. It deletes e-mail without downloading it: YOU MAY
 * PERMANENTLY LOSE DATA!
 * 
 * Typical usage: 1) Look at the subject lines for the big messages you've got
 * java PopClean -host host -user user -pass pass -size 100000
 * 
 * 2) Create a regular expression to match viral subject lines, and use it to
 * delete large matching messages java PopClean -host h -user u -pass p -delete
 * -size 100000 \ -subject 'Thank you!|Re: Your application' This will ask for
 * confirmation before proceeding.
 * 
 * 3) If you're confident that all big messages are virus-infected, then you can
 * skip the -subject argument and delete on size alone java PopClean -host h
 * -user u -pass p -delete -size 100000 This will ask for confirmation before
 * proceeding.
 */
public class PopClean {
    static Socket s = null; // The connection to the server

    static BufferedReader in = null; // To read lines from the server

    static PrintWriter out = null; // To write to the server

    static boolean debug = false; // Are we in debug mode?

    public static void main(String args[]) {
        try {
            String hostname = null, username = null, password = null;
            int port = 110;
            int sizelimit = -1;
            String subjectPattern = null;
            Pattern pattern = null;
            Matcher matcher = null;
            boolean delete = false;
            boolean confirm = true;

            // Handle command-line arguments
            for (int i = 0; i < args.length; i++) {
                if (args[i].equals("-user"))
                    username = args[++i];
                else if (args[i].equals("-pass"))
                    password = args[++i];
                else if (args[i].equals("-host"))
                    hostname = args[++i];
                else if (args[i].equals("-port"))
                    port = Integer.parseInt(args[++i]);
                else if (args[i].equals("-size"))
                    sizelimit = Integer.parseInt(args[++i]);
                else if (args[i].equals("-subject"))
                    subjectPattern = args[++i];
                else if (args[i].equals("-debug"))
                    debug = true;
                else if (args[i].equals("-delete"))
                    delete = true;
                else if (args[i].equals("-force")) // don't confirm
                    confirm = false;
            }

            // Verify them
            if (hostname == null || username == null || password == null || sizelimit == -1)
                usage();

            // Make sure the pattern is a valid regexp
            if (subjectPattern != null) {
                pattern = Pattern.compile(subjectPattern);
                matcher = pattern.matcher("");
            }

            // Say what we are going to do
            System.out
                    .println("Connecting to " + hostname + " on port " + port + " with username " + username + ".");
            if (delete) {
                System.out.println("Will delete all messages longer than " + sizelimit + " bytes");
                if (subjectPattern != null)
                    System.out.println("that have a subject matching: [" + subjectPattern + "]");
            } else {
                System.out.println("Will list subject lines for messages " + "longer than " + sizelimit + " bytes");
                if (subjectPattern != null)
                    System.out.println("that have a subject matching: [" + subjectPattern + "]");
            }

            // If asked to delete, ask for confirmation unless -force is given
            if (delete && confirm) {
                System.out.println();
                System.out.print("Do you want to proceed (y/n) [n]: ");
                System.out.flush();
                BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
                String response = console.readLine();
                if (!response.equals("y")) {
                    System.out.println("No messages deleted.");
                    System.exit(0);
                }
            }

            // Connect to the server, and set up streams
            s = new Socket(hostname, port);
            in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            out = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));

            // Read the welcome message from the server, confirming it is OK.
            System.out.println("Connected: " + checkResponse());

            // Now log in
            send("USER " + username); // Send username, wait for response
            send("PASS " + password); // Send password, wait for response
            System.out.println("Logged in");

            // Check how many messages are waiting, and report it
            String stat = send("STAT");
            StringTokenizer t = new StringTokenizer(stat);
            System.out.println(t.nextToken() + " messages in mailbox.");
            System.out.println("Total size: " + t.nextToken());

            // Get a list of message numbers and sizes
            send("LIST"); // Send LIST command, wait for OK response.
            // Now read lines from the server until we get . by itself
            List msgs = new ArrayList();
            String line;
            for (;;) {
                line = in.readLine();
                if (line == null)
                    throw new IOException("Unexpected EOF");
                if (line.equals("."))
                    break;
                msgs.add(line);
            }

            // Now loop through the lines we read one at a time.
            // Each line should specify the message number and its size.
            int nummsgs = msgs.size();
            for (int i = 0; i < nummsgs; i++) {
                String m = (String) msgs.get(i);
                StringTokenizer st = new StringTokenizer(m);
                int msgnum = Integer.parseInt(st.nextToken());
                int msgsize = Integer.parseInt(st.nextToken());

                // If the message is too small, ignore it.
                if (msgsize <= sizelimit)
                    continue;

                // If we're listing messages, or matching subject lines
                // find the subject line for this message
                String subject = null;
                if (!delete || pattern != null) {
                    subject = getSubject(msgnum); // get the subject line

                    // If we couldn't find a subject, skip the message
                    if (subject == null)
                        continue;

                    // If this subject does not match the pattern, then
                    // skip the message
                    if (pattern != null) {
                        matcher.reset(subject);
                        if (!matcher.matches())
                            continue;
                    }

                    // If we are listing, list this message
                    if (!delete) {
                        System.out.println("Subject " + msgnum + ": " + subject);
                        continue; // so we never delete it
                    }
                }

                // If we were asked to delete, then delete the message
                if (delete) {
                    send("DELE " + msgnum);
                    if (pattern == null)
                        System.out.println("Deleted message " + msgnum);
                    else
                        System.out.println("Deleted message " + msgnum + ": " + subject);
                }
            }

            // When we're done, log out and shutdown the connection
            shutdown();
        } catch (Exception e) {
            // If anything goes wrong print exception and show usage
            System.err.println(e);
            usage();
            // Always try to shutdown nicely so the server doesn't hang on us
            shutdown();
        }
    }

    // Explain how to use the program
    public static void usage() {
        System.err.println("java PopClean <options>");
        System.err.println("Options are:\n" + "-host <hostname>  # Required\n"
                + "-port <port>      # Optional; default is 110\n" + "-user <username>  # Required\n"
                + "-pass <password>  # Required and sent as cleartext; APOP not supported\n"
                + "-size <limit>     # Message size in bytes. Shorter messages are ignored.\n"
                + "-subject <regexp> # Optional java.util.regex.Pattern regular expression\n"
                + "                  # only messages with a matching Subject line are deleted\n"
                + "-delete           # Delete messages; the default is just to list them\n"
                + "-force            # Don't ask for confirmation before deleting\n"
                + "-debug            # Display POP3 protocol requests and responses\n");

        System.exit(1);
    }

    // Send a POP3 command to the server and return its response
    public static String send(String cmd) throws IOException {
        if (debug)
            System.out.println(">>>" + cmd);
        out.print(cmd); // Send command
        out.print("\r\n"); // and line terminator.
        out.flush(); // Send it now!
        String response = checkResponse(); // Get the response.
        if (debug)
            System.out.println("<<<+OK " + response);
        return response;
    }

    // Wait for a response and make sure it is an "OK" response.
    public static String checkResponse() throws IOException {
        String response;
        for (;;) {
            response = in.readLine();
            if (response == null)
                throw new IOException("Server unexpectedly closed connection");
            else if (response.startsWith("-ERR"))
                throw new IOException("Error from server: " + response);
            else if (response.startsWith("+OK"))
                return response.substring(3);
        }
    }

    // Ask the server to send the headers of the numbered message.
    // Look through them for the Subject header and return its content.
    public static String getSubject(int msgnum) throws IOException {
        send("TOP " + msgnum + " 0");
        String subject = null, line;
        for (;;) {
            line = in.readLine();
            if (line == null)
                throw new IOException("Unexpected EOF");
            if (line.startsWith("Subject: "))
                subject = line.substring(9);
            if (line.equals("."))
                break;
        }
        return subject;
    }

    // Disconnect nicely from the POP server.
    // This method is called for normal termination and exceptions.
    public static void shutdown() {
        try {
            if (out != null) {
                send("QUIT");
                out.close();
            }
            if (in != null)
                in.close();
            if (s != null)
                s.close();
        } catch (IOException e) {
        }
    }
}