| /* |
| * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Distribution License v. 1.0, which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| import java.util.*; |
| import java.util.concurrent.atomic.*; |
| import java.io.*; |
| import javax.mail.*; |
| import javax.mail.event.*; |
| import javax.mail.internet.*; |
| import javax.activation.*; |
| |
| import com.sun.mail.imap.*; |
| |
| /** |
| * Test program for IDLE support in IMAP provider. |
| * |
| * Run several threads that access the folder's connection |
| * while another thread runs the IDLE command. A timer |
| * thread checks that each thread is making progress, to |
| * detect deadlock. |
| * |
| * XXX - Should have another thread add messages to the folder |
| * to test the new message notification works properly. |
| */ |
| public class testidle { |
| |
| public static Store store; |
| public static Folder folder; |
| public static boolean showStructure = false; |
| public static boolean saveAttachments = false; |
| public static int attnum = 0; |
| public static int totalTime; |
| |
| public static final AtomicBoolean stop = new AtomicBoolean(false); |
| public static final AtomicInteger folderProgress = new AtomicInteger(); |
| public static final AtomicInteger msgProgress = new AtomicInteger(); |
| |
| public static void main(String argv[]) { |
| if (argv.length != 5) { |
| System.out.println( |
| "Usage: testidle <host> <user> <password> <mbox> <time>"); |
| System.exit(1); |
| } |
| |
| try { |
| Properties props = System.getProperties(); |
| |
| // Get a Session object |
| Session session = Session.getInstance(props, null); |
| // session.setDebug(true); |
| |
| // Get a Store object |
| store = session.getStore("imap"); |
| |
| store.addStoreListener(new StoreListener() { |
| public void notification(StoreEvent e) { |
| System.out.println("StoreEvent: type " + |
| e.getMessageType() + ", message " + |
| e.getMessage()); |
| } |
| }); |
| |
| // Connect |
| store.connect(argv[0], argv[1], argv[2]); |
| |
| // Open a Folder |
| folder = store.getFolder(argv[3]); |
| if (folder == null || !folder.exists()) { |
| System.out.println("Invalid folder"); |
| System.exit(1); |
| } |
| |
| folder.open(Folder.READ_WRITE); |
| |
| // Add messageCountListener to listen for new messages |
| folder.addMessageCountListener(new MessageCountAdapter() { |
| public void messagesAdded(MessageCountEvent ev) { |
| Message[] msgs = ev.getMessages(); |
| System.out.println("Got " + msgs.length + " new messages"); |
| |
| // Just dump out the new messages |
| for (int i = 0; i < msgs.length; i++) { |
| try { |
| System.out.println("-----"); |
| System.out.println("Message " + |
| msgs[i].getMessageNumber() + ":"); |
| msgs[i].writeTo(System.out); |
| } catch (IOException ioex) { |
| ioex.printStackTrace(); |
| } catch (MessagingException mex) { |
| mex.printStackTrace(); |
| } |
| } |
| } |
| }); |
| |
| totalTime = Integer.parseInt(argv[4]); |
| |
| new Thread("timer") { |
| public void run() { |
| timer(); |
| } |
| }.start(); |
| |
| new Thread("message reader") { |
| public void run() { |
| readMessages(); |
| } |
| }.start(); |
| |
| new Thread("folder reader") { |
| public void run() { |
| readFolder(); |
| } |
| }.start(); |
| |
| new Thread("store idle") { |
| public void run() { |
| storeIdle(); |
| } |
| }.start(); |
| |
| |
| /* |
| * make sure two threads running idle works properly |
| new Thread("idle") { |
| public void run() { |
| try { |
| doIdle(); |
| } catch (MessagingException mex) { } |
| } |
| }.start(); |
| */ |
| |
| doIdle(); |
| |
| System.out.println("connected " + store.isConnected()); |
| |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Run the idle command until told to stop. |
| */ |
| public static void doIdle() throws MessagingException { |
| boolean supportsIdle = false; |
| try { |
| if (folder instanceof IMAPFolder) { |
| IMAPFolder f = (IMAPFolder)folder; |
| f.idle(); |
| supportsIdle = true; |
| } |
| } catch (FolderClosedException fex) { |
| throw fex; |
| } catch (MessagingException mex) { |
| supportsIdle = false; |
| } |
| while (!stop.get()) { |
| if (supportsIdle && folder instanceof IMAPFolder) { |
| IMAPFolder f = (IMAPFolder)folder; |
| f.idle(); |
| /* |
| System.out.println("IDLE done in " + |
| Thread.currentThread().getName()); |
| */ |
| } else { |
| try { |
| Thread.sleep(1000); // sleep for 1000 milliseconds |
| } catch (InterruptedException ex) { } |
| |
| // This is to force the IMAP server to send us |
| // EXISTS notifications. |
| folder.getMessageCount(); |
| } |
| } |
| } |
| |
| /** |
| * Monitor progress of threads and tell them to stop |
| * when their time is up. |
| */ |
| public static void timer() { |
| long tend = System.currentTimeMillis() + totalTime; |
| int fpcnt = folderProgress.get(); |
| int mpcnt = msgProgress.get(); |
| while (System.currentTimeMillis() < tend) { |
| try { |
| Thread.sleep(1000); |
| } catch (InterruptedException ex) { } |
| int nfpcnt = folderProgress.get(); |
| int nmpcnt = msgProgress.get(); |
| if (!(nfpcnt > fpcnt && nmpcnt > mpcnt)) { |
| System.out.println("THREAD STUCK?"); |
| System.out.printf("fpcnt %d nfpcnt %d\n", fpcnt, nfpcnt); |
| System.out.printf("mpcnt %d nmpcnt %d\n", mpcnt, nmpcnt); |
| } |
| fpcnt = nfpcnt; |
| mpcnt = nmpcnt; |
| } |
| System.out.println("STOPPING"); |
| stop.set(true); |
| try { |
| folder.getUnreadMessageCount(); // force IDLE to terminate |
| } catch (MessagingException mex) { } |
| } |
| |
| /** |
| * Read all the messages in the folder and access all their content. |
| */ |
| public static void readMessages() { |
| try { |
| while (!stop.get()) { |
| int cnt = folder.getMessageCount(); |
| for (int i = 1; i <= cnt; i++) { |
| //System.out.println("dump " + i); |
| Message msg = folder.getMessage(i); |
| dumpEnvelope(msg); |
| msgProgress.incrementAndGet(); |
| try { |
| Thread.sleep(25); |
| } catch (InterruptedException ex) { } |
| } |
| } |
| System.out.println("messages DONE"); |
| } catch (Exception ex) { |
| System.out.println(ex); |
| } |
| } |
| |
| /** |
| * Perform folder commands to compete with the message |
| * access commands. |
| */ |
| public static void readFolder() { |
| try { |
| while (!stop.get()) { |
| int cnt = folder.getUnreadMessageCount(); |
| store.isConnected(); // poke the store too |
| folderProgress.incrementAndGet(); |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException ex) { } |
| } |
| System.out.println("folder DONE"); |
| } catch (MessagingException mex) { |
| System.out.println(mex); |
| } |
| } |
| |
| /** |
| * Run the idle command until told to stop. |
| */ |
| public static void storeIdle() { |
| boolean supportsIdle = false; |
| try { |
| if (store instanceof IMAPStore) { |
| IMAPStore s = (IMAPStore)store; |
| s.idle(); |
| supportsIdle = true; |
| } |
| } catch (MessagingException mex) { |
| supportsIdle = false; |
| } |
| try { |
| while (!stop.get()) { |
| if (supportsIdle && store instanceof IMAPStore) { |
| IMAPStore s = (IMAPStore)store; |
| s.idle(); |
| /* |
| */ |
| System.out.println("IDLE done in " + |
| Thread.currentThread().getName()); |
| /* |
| */ |
| } else { |
| try { |
| Thread.sleep(1000); // sleep for 1000 milliseconds |
| } catch (InterruptedException ex) { } |
| } |
| } |
| } catch (MessagingException mex) { |
| System.out.println(mex); |
| } |
| } |
| |
| /** |
| * Dump contents of message part. |
| * (Copied from msgshow.java) |
| */ |
| public static void dumpPart(Part p) throws Exception { |
| if (p instanceof Message) |
| dumpEnvelope((Message)p); |
| |
| /** Dump input stream .. |
| |
| InputStream is = p.getInputStream(); |
| // If "is" is not already buffered, wrap a BufferedInputStream |
| // around it. |
| if (!(is instanceof BufferedInputStream)) |
| is = new BufferedInputStream(is); |
| int c; |
| while ((c = is.read()) != -1) |
| System.out.write(c); |
| |
| **/ |
| |
| String ct = p.getContentType(); |
| try { |
| pr("CONTENT-TYPE: " + (new ContentType(ct)).toString()); |
| } catch (ParseException pex) { |
| pr("BAD CONTENT-TYPE: " + ct); |
| } |
| String filename = p.getFileName(); |
| if (filename != null) |
| pr("FILENAME: " + filename); |
| |
| /* |
| * Using isMimeType to determine the content type avoids |
| * fetching the actual content data until we need it. |
| */ |
| if (p.isMimeType("text/plain")) { |
| pr("This is plain text"); |
| pr("---------------------------"); |
| if (!showStructure && !saveAttachments) |
| System.out.println((String)p.getContent()); |
| } else if (p.isMimeType("multipart/*")) { |
| pr("This is a Multipart"); |
| pr("---------------------------"); |
| Multipart mp = (Multipart)p.getContent(); |
| level++; |
| int count = mp.getCount(); |
| for (int i = 0; i < count; i++) |
| dumpPart(mp.getBodyPart(i)); |
| level--; |
| } else if (p.isMimeType("message/rfc822")) { |
| pr("This is a Nested Message"); |
| pr("---------------------------"); |
| level++; |
| dumpPart((Part)p.getContent()); |
| level--; |
| } else { |
| if (!showStructure && !saveAttachments) { |
| /* |
| * If we actually want to see the data, and it's not a |
| * MIME type we know, fetch it and check its Java type. |
| */ |
| Object o = p.getContent(); |
| if (o instanceof String) { |
| pr("This is a string"); |
| pr("---------------------------"); |
| System.out.println((String)o); |
| } else if (o instanceof InputStream) { |
| pr("This is just an input stream"); |
| pr("---------------------------"); |
| InputStream is = (InputStream)o; |
| int c; |
| while ((c = is.read()) != -1) |
| System.out.write(c); |
| } else { |
| pr("This is an unknown type"); |
| pr("---------------------------"); |
| pr(o.toString()); |
| } |
| } else { |
| // just a separator |
| pr("---------------------------"); |
| } |
| } |
| |
| /* |
| * If we're saving attachments, write out anything that |
| * looks like an attachment into an appropriately named |
| * file. Don't overwrite existing files to prevent |
| * mistakes. |
| */ |
| if (saveAttachments && level != 0 && !p.isMimeType("multipart/*")) { |
| String disp = p.getDisposition(); |
| // many mailers don't include a Content-Disposition |
| if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT)) { |
| if (filename == null) |
| filename = "Attachment" + attnum++; |
| pr("Saving attachment to file " + filename); |
| try { |
| File f = new File(filename); |
| if (f.exists()) |
| // XXX - could try a series of names |
| throw new IOException("file exists"); |
| ((MimeBodyPart)p).saveFile(f); |
| } catch (IOException ex) { |
| pr("Failed to save attachment: " + ex); |
| } |
| pr("---------------------------"); |
| } |
| } |
| } |
| |
| public static void dumpEnvelope(Message m) throws Exception { |
| pr("This is the message envelope"); |
| pr("---------------------------"); |
| Address[] a; |
| // FROM |
| if ((a = m.getFrom()) != null) { |
| for (int j = 0; j < a.length; j++) |
| pr("FROM: " + a[j].toString()); |
| } |
| |
| // TO |
| if ((a = m.getRecipients(Message.RecipientType.TO)) != null) { |
| for (int j = 0; j < a.length; j++) { |
| pr("TO: " + a[j].toString()); |
| InternetAddress ia = (InternetAddress)a[j]; |
| if (ia.isGroup()) { |
| InternetAddress[] aa = ia.getGroup(false); |
| for (int k = 0; k < aa.length; k++) |
| pr(" GROUP: " + aa[k].toString()); |
| } |
| } |
| } |
| |
| // SUBJECT |
| pr("SUBJECT: " + m.getSubject()); |
| |
| // DATE |
| Date d = m.getSentDate(); |
| pr("SendDate: " + |
| (d != null ? d.toString() : "UNKNOWN")); |
| |
| // FLAGS |
| Flags flags = m.getFlags(); |
| StringBuffer sb = new StringBuffer(); |
| Flags.Flag[] sf = flags.getSystemFlags(); // get the system flags |
| |
| boolean first = true; |
| for (int i = 0; i < sf.length; i++) { |
| String s; |
| Flags.Flag f = sf[i]; |
| if (f == Flags.Flag.ANSWERED) |
| s = "\\Answered"; |
| else if (f == Flags.Flag.DELETED) |
| s = "\\Deleted"; |
| else if (f == Flags.Flag.DRAFT) |
| s = "\\Draft"; |
| else if (f == Flags.Flag.FLAGGED) |
| s = "\\Flagged"; |
| else if (f == Flags.Flag.RECENT) |
| s = "\\Recent"; |
| else if (f == Flags.Flag.SEEN) |
| s = "\\Seen"; |
| else |
| continue; // skip it |
| if (first) |
| first = false; |
| else |
| sb.append(' '); |
| sb.append(s); |
| } |
| |
| String[] uf = flags.getUserFlags(); // get the user flag strings |
| for (int i = 0; i < uf.length; i++) { |
| if (first) |
| first = false; |
| else |
| sb.append(' '); |
| sb.append(uf[i]); |
| } |
| pr("FLAGS: " + sb.toString()); |
| |
| // X-MAILER |
| String[] hdrs = m.getHeader("X-Mailer"); |
| if (hdrs != null) |
| pr("X-Mailer: " + hdrs[0]); |
| else |
| pr("X-Mailer NOT available"); |
| } |
| |
| static String indentStr = " "; |
| static int level = 0; |
| |
| /** |
| * Print a, possibly indented, string. |
| */ |
| public static void pr(String s) { |
| /* |
| if (showStructure) |
| System.out.print(indentStr.substring(0, level * 2)); |
| System.out.println(s); |
| */ |
| } |
| } |