1 /*
2  * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 import java.util.*;
33 import java.io.*;
34 import javax.mail.*;
35 import javax.mail.event.*;
36 import javax.mail.internet.*;
37 
38 /*
39  * Demo app that exercises the Message interfaces.
40  * Show information about and contents of messages.
41  *
42  * @author John Mani
43  * @author Bill Shannon
44  */
45 
46 public class msgshow {
47 
48     static String protocol;
49     static String host = null;
50     static String user = null;
51     static String password = null;
52     static String mbox = null;
53     static String url = null;
54     static int port = -1;
55     static boolean verbose = false;
56     static boolean debug = false;
57     static boolean showStructure = false;
58     static boolean showMessage = false;
59     static boolean showAlert = false;
60     static boolean saveAttachments = false;
61     static int attnum = 1;
62 
main(String argv[])63     public static void main(String argv[]) {
64 	int optind;
65 	InputStream msgStream = System.in;
66 
67 	for (optind = 0; optind < argv.length; optind++) {
68 	    if (argv[optind].equals("-T")) {
69 		protocol = argv[++optind];
70 	    } else if (argv[optind].equals("-H")) {
71 		host = argv[++optind];
72 	    } else if (argv[optind].equals("-U")) {
73 		user = argv[++optind];
74 	    } else if (argv[optind].equals("-P")) {
75 		password = argv[++optind];
76 	    } else if (argv[optind].equals("-v")) {
77 		verbose = true;
78 	    } else if (argv[optind].equals("-D")) {
79 		debug = true;
80 	    } else if (argv[optind].equals("-f")) {
81 		mbox = argv[++optind];
82 	    } else if (argv[optind].equals("-L")) {
83 		url = argv[++optind];
84 	    } else if (argv[optind].equals("-p")) {
85 		port = Integer.parseInt(argv[++optind]);
86 	    } else if (argv[optind].equals("-s")) {
87 		showStructure = true;
88 	    } else if (argv[optind].equals("-S")) {
89 		saveAttachments = true;
90 	    } else if (argv[optind].equals("-m")) {
91 		showMessage = true;
92 	    } else if (argv[optind].equals("-a")) {
93 		showAlert = true;
94 	    } else if (argv[optind].equals("--")) {
95 		optind++;
96 		break;
97 	    } else if (argv[optind].startsWith("-")) {
98 		System.out.println(
99 "Usage: msgshow [-L url] [-T protocol] [-H host] [-p port] [-U user]");
100 		System.out.println(
101 "\t[-P password] [-f mailbox] [msgnum ...] [-v] [-D] [-s] [-S] [-a]");
102 		System.out.println(
103 "or     msgshow -m [-v] [-D] [-s] [-S] [-f msg-file]");
104 		System.exit(1);
105 	    } else {
106 		break;
107 	    }
108 	}
109 
110 	try {
111 	    // Get a Properties object
112 	    Properties props = System.getProperties();
113 
114 	    // Get a Session object
115 	    Session session = Session.getInstance(props, null);
116 	    session.setDebug(debug);
117 
118 	    if (showMessage) {
119 		MimeMessage msg;
120 		if (mbox != null)
121 		    msg = new MimeMessage(session,
122 			new BufferedInputStream(new FileInputStream(mbox)));
123 		else
124 		    msg = new MimeMessage(session, msgStream);
125 		dumpPart(msg);
126 		System.exit(0);
127 	    }
128 
129 	    // Get a Store object
130 	    Store store = null;
131 	    if (url != null) {
132 		URLName urln = new URLName(url);
133 		store = session.getStore(urln);
134 		if (showAlert) {
135 		    store.addStoreListener(new StoreListener() {
136 			public void notification(StoreEvent e) {
137 			    String s;
138 			    if (e.getMessageType() == StoreEvent.ALERT)
139 				s = "ALERT: ";
140 			    else
141 				s = "NOTICE: ";
142 			    System.out.println(s + e.getMessage());
143 			}
144 		    });
145 		}
146 		store.connect();
147 	    } else {
148 		if (protocol != null)
149 		    store = session.getStore(protocol);
150 		else
151 		    store = session.getStore();
152 
153 		// Connect
154 		if (host != null || user != null || password != null)
155 		    store.connect(host, port, user, password);
156 		else
157 		    store.connect();
158 	    }
159 
160 
161 	    // Open the Folder
162 
163 	    Folder folder = store.getDefaultFolder();
164 	    if (folder == null) {
165 		System.out.println("No default folder");
166 		System.exit(1);
167 	    }
168 
169 	    if (mbox == null)
170 		mbox = "INBOX";
171 	    folder = folder.getFolder(mbox);
172 	    if (folder == null) {
173 		System.out.println("Invalid folder");
174 		System.exit(1);
175 	    }
176 
177 	    // try to open read/write and if that fails try read-only
178 	    try {
179 		folder.open(Folder.READ_WRITE);
180 	    } catch (MessagingException ex) {
181 		folder.open(Folder.READ_ONLY);
182 	    }
183 	    int totalMessages = folder.getMessageCount();
184 
185 	    if (totalMessages == 0) {
186 		System.out.println("Empty folder");
187 		folder.close(false);
188 		store.close();
189 		System.exit(1);
190 	    }
191 
192 	    if (verbose) {
193 		int newMessages = folder.getNewMessageCount();
194 		System.out.println("Total messages = " + totalMessages);
195 		System.out.println("New messages = " + newMessages);
196 		System.out.println("-------------------------------");
197 	    }
198 
199 	    if (optind >= argv.length) {
200 		// Attributes & Flags for all messages ..
201 		Message[] msgs = folder.getMessages();
202 
203 		// Use a suitable FetchProfile
204 		FetchProfile fp = new FetchProfile();
205 		fp.add(FetchProfile.Item.ENVELOPE);
206 		fp.add(FetchProfile.Item.FLAGS);
207 		fp.add("X-Mailer");
208 		folder.fetch(msgs, fp);
209 
210 		for (int i = 0; i < msgs.length; i++) {
211 		    System.out.println("--------------------------");
212 		    System.out.println("MESSAGE #" + (i + 1) + ":");
213 		    dumpEnvelope(msgs[i]);
214 		    // dumpPart(msgs[i]);
215 		}
216 	    } else {
217 		while (optind < argv.length) {
218 		    int msgnum = Integer.parseInt(argv[optind++]);
219 		    System.out.println("Getting message number: " + msgnum);
220 		    Message m = null;
221 
222 		    try {
223 			m = folder.getMessage(msgnum);
224 			dumpPart(m);
225 		    } catch (IndexOutOfBoundsException iex) {
226 			System.out.println("Message number out of range");
227 		    }
228 		}
229 	    }
230 
231 	    folder.close(false);
232 	    store.close();
233 	} catch (Exception ex) {
234 	    System.out.println("Oops, got exception! " + ex.getMessage());
235 	    ex.printStackTrace();
236 	    System.exit(1);
237 	}
238 	System.exit(0);
239     }
240 
dumpPart(Part p)241     public static void dumpPart(Part p) throws Exception {
242 	if (p instanceof Message)
243 	    dumpEnvelope((Message)p);
244 
245 	/** Dump input stream ..
246 
247 	InputStream is = p.getInputStream();
248 	// If "is" is not already buffered, wrap a BufferedInputStream
249 	// around it.
250 	if (!(is instanceof BufferedInputStream))
251 	    is = new BufferedInputStream(is);
252 	int c;
253 	while ((c = is.read()) != -1)
254 	    System.out.write(c);
255 
256 	**/
257 
258 	String ct = p.getContentType();
259 	try {
260 	    pr("CONTENT-TYPE: " + (new ContentType(ct)).toString());
261 	} catch (ParseException pex) {
262 	    pr("BAD CONTENT-TYPE: " + ct);
263 	}
264 	String filename = p.getFileName();
265 	if (filename != null)
266 	    pr("FILENAME: " + filename);
267 
268 	/*
269 	 * Using isMimeType to determine the content type avoids
270 	 * fetching the actual content data until we need it.
271 	 */
272 	if (p.isMimeType("text/plain")) {
273 	    pr("This is plain text");
274 	    pr("---------------------------");
275 	    if (!showStructure && !saveAttachments)
276 		System.out.println((String)p.getContent());
277 	} else if (p.isMimeType("multipart/*")) {
278 	    pr("This is a Multipart");
279 	    pr("---------------------------");
280 	    Multipart mp = (Multipart)p.getContent();
281 	    level++;
282 	    int count = mp.getCount();
283 	    for (int i = 0; i < count; i++)
284 		dumpPart(mp.getBodyPart(i));
285 	    level--;
286 	} else if (p.isMimeType("message/rfc822")) {
287 	    pr("This is a Nested Message");
288 	    pr("---------------------------");
289 	    level++;
290 	    dumpPart((Part)p.getContent());
291 	    level--;
292 	} else {
293 	    if (!showStructure && !saveAttachments) {
294 		/*
295 		 * If we actually want to see the data, and it's not a
296 		 * MIME type we know, fetch it and check its Java type.
297 		 */
298 		Object o = p.getContent();
299 		if (o instanceof String) {
300 		    pr("This is a string");
301 		    pr("---------------------------");
302 		    System.out.println((String)o);
303 		} else if (o instanceof InputStream) {
304 		    pr("This is just an input stream");
305 		    pr("---------------------------");
306 		    InputStream is = (InputStream)o;
307 		    int c;
308 		    while ((c = is.read()) != -1)
309 			System.out.write(c);
310 		} else {
311 		    pr("This is an unknown type");
312 		    pr("---------------------------");
313 		    pr(o.toString());
314 		}
315 	    } else {
316 		// just a separator
317 		pr("---------------------------");
318 	    }
319 	}
320 
321 	/*
322 	 * If we're saving attachments, write out anything that
323 	 * looks like an attachment into an appropriately named
324 	 * file.  Don't overwrite existing files to prevent
325 	 * mistakes.
326 	 */
327 	if (saveAttachments && level != 0 && p instanceof MimeBodyPart &&
328 		!p.isMimeType("multipart/*")) {
329 	    String disp = p.getDisposition();
330 	    // many mailers don't include a Content-Disposition
331 	    if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT)) {
332 		if (filename == null)
333 		    filename = "Attachment" + attnum++;
334 		pr("Saving attachment to file " + filename);
335 		try {
336 		    File f = new File(filename);
337 		    if (f.exists())
338 			// XXX - could try a series of names
339 			throw new IOException("file exists");
340 		    ((MimeBodyPart)p).saveFile(f);
341 		} catch (IOException ex) {
342 		    pr("Failed to save attachment: " + ex);
343 		}
344 		pr("---------------------------");
345 	    }
346 	}
347     }
348 
dumpEnvelope(Message m)349     public static void dumpEnvelope(Message m) throws Exception {
350 	pr("This is the message envelope");
351 	pr("---------------------------");
352 	Address[] a;
353 	// FROM
354 	if ((a = m.getFrom()) != null) {
355 	    for (int j = 0; j < a.length; j++)
356 		pr("FROM: " + a[j].toString());
357 	}
358 
359 	// REPLY TO
360 	if ((a = m.getReplyTo()) != null) {
361 	    for (int j = 0; j < a.length; j++)
362 		pr("REPLY TO: " + a[j].toString());
363 	}
364 
365 	// TO
366 	if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
367 	    for (int j = 0; j < a.length; j++) {
368 		pr("TO: " + a[j].toString());
369 		InternetAddress ia = (InternetAddress)a[j];
370 		if (ia.isGroup()) {
371 		    InternetAddress[] aa = ia.getGroup(false);
372 		    for (int k = 0; k < aa.length; k++)
373 			pr("  GROUP: " + aa[k].toString());
374 		}
375 	    }
376 	}
377 
378 	// SUBJECT
379 	pr("SUBJECT: " + m.getSubject());
380 
381 	// DATE
382 	Date d = m.getSentDate();
383 	pr("SendDate: " +
384 	    (d != null ? d.toString() : "UNKNOWN"));
385 
386 	// FLAGS
387 	Flags flags = m.getFlags();
388 	StringBuffer sb = new StringBuffer();
389 	Flags.Flag[] sf = flags.getSystemFlags(); // get the system flags
390 
391 	boolean first = true;
392 	for (int i = 0; i < sf.length; i++) {
393 	    String s;
394 	    Flags.Flag f = sf[i];
395 	    if (f == Flags.Flag.ANSWERED)
396 		s = "\\Answered";
397 	    else if (f == Flags.Flag.DELETED)
398 		s = "\\Deleted";
399 	    else if (f == Flags.Flag.DRAFT)
400 		s = "\\Draft";
401 	    else if (f == Flags.Flag.FLAGGED)
402 		s = "\\Flagged";
403 	    else if (f == Flags.Flag.RECENT)
404 		s = "\\Recent";
405 	    else if (f == Flags.Flag.SEEN)
406 		s = "\\Seen";
407 	    else
408 		continue;	// skip it
409 	    if (first)
410 		first = false;
411 	    else
412 		sb.append(' ');
413 	    sb.append(s);
414 	}
415 
416 	String[] uf = flags.getUserFlags(); // get the user flag strings
417 	for (int i = 0; i < uf.length; i++) {
418 	    if (first)
419 		first = false;
420 	    else
421 		sb.append(' ');
422 	    sb.append(uf[i]);
423 	}
424 	pr("FLAGS: " + sb.toString());
425 
426 	// X-MAILER
427 	String[] hdrs = m.getHeader("X-Mailer");
428 	if (hdrs != null)
429 	    pr("X-Mailer: " + hdrs[0]);
430 	else
431 	    pr("X-Mailer NOT available");
432     }
433 
434     static String indentStr = "                                               ";
435     static int level = 0;
436 
437     /**
438      * Print a, possibly indented, string.
439      */
pr(String s)440     public static void pr(String s) {
441 	if (showStructure)
442 	    System.out.print(indentStr.substring(0, level * 2));
443 	System.out.println(s);
444     }
445 }
446