-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIMAPHandler.java
More file actions
429 lines (351 loc) · 11.6 KB
/
IMAPHandler.java
File metadata and controls
429 lines (351 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
import java.io.*;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.security.cert.Certificate;
import java.util.ArrayList;
import javax.management.relation.RelationServiceNotRegisteredException;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.util.regex.*;
import org.omg.PortableServer.ThreadPolicyOperations;
public class IMAPHandler
{
//////////////////////////////
// Private Static Constants //
//////////////////////////////
private static final int DEF_OUTPUT_STREAM_SIZE = 8192;
private static boolean DEF_AUTH_FLAG_SETTING = false;
/* Default exception messages */
private static final String DEF_PASSWORD_REQ_MSG = "Please enter your password:";
private static final String DEF_DIRECTORY_QUALIFIER = "HasNoChildren";
/////////////////////////
// Private Member Data //
/////////////////////////
/* Socket specific data. */
private String[] theSuites;
private SSLSocketFactory theSocketFactory;
private SSLSocket theSocket;
private SSLSession theSession;
private Certificate[] theCertChain;
/* Message specific data. */
private OutputStream theOutputStream;
private BufferedReader theInputBuffer;
private BufferedReader theStdinBuffer;
/* Internet address specific data. */
private InetAddress theServer;
private String thePort;
private String thePassword;
private String theLogin;
private boolean theAuthenticationFlag;
private String[] theFolders;
private boolean theAllFlag;
private boolean deleteFlag;
////////////////////////////
// Private Member Methods //
////////////////////////////
private void defaultInitialization()
{
theAuthenticationFlag = DEF_AUTH_FLAG_SETTING;
theSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
try
{
theSocket = (SSLSocket) theSocketFactory.createSocket( theServer, Integer.parseInt(thePort) );
theSuites = theSocket.getSupportedCipherSuites();
theSocket.setEnabledCipherSuites(theSuites);
theSocket.addHandshakeCompletedListener(new HandShakeListener());
theSession = theSocket.getSession();
theCertChain = theSession.getPeerCertificates();
theOutputStream = new BufferedOutputStream(theSocket.getOutputStream(), DEF_OUTPUT_STREAM_SIZE );
theInputBuffer = new BufferedReader(new InputStreamReader(theSocket.getInputStream() ) );
theStdinBuffer = new BufferedReader( new InputStreamReader( System.in ) );
/*
* Keep soliciting a password from stdin while the password is
* null.
*/
while( thePassword.equals(null) )
{
requestPassword(theStdinBuffer);
}
}
catch (NumberFormatException inException)
{
inException.printStackTrace();
}
catch (IOException inException)
{
inException.printStackTrace();
}
return;
}
private void requestPassword( BufferedReader inReader )
{
/*Solicit a password from the user using the given buffered input reader.*/
System.out.println(DEF_PASSWORD_REQ_MSG);
try
{
thePassword = inReader.readLine();
}
catch (IOException inException) {
inException.printStackTrace();
}
return;
}
///////////////////////////
// Public Member Methods //
///////////////////////////
public IMAPHandler(InetAddress inServer, String inPort, String inLogin, String inPassword,
String [] inFolders, boolean inAllFlag, boolean inDeleteFlag)
{
/* Member data get the parameter(s). */
theServer = inServer;
thePort = inPort;
theLogin = inLogin;
thePassword = inPassword;
theFolders = inFolders;
theAllFlag = inAllFlag;
deleteFlag = inDeleteFlag;
defaultInitialization();
return;
}
public void login()
{
/* Assemble the login command string from the object fields. */
final String loginCommand = "$ Login " + theLogin + " " + thePassword + "\r\n";
/* Attempt to login. Throw an error at failure. */
try
{
sendCommand (loginCommand);
/* Print authentication message. */
System.out.println(theInputBuffer.readLine ());
System.out.println(theInputBuffer.readLine ());
System.out.println(theInputBuffer.readLine ());
}
catch (IOException inException) {
inException.printStackTrace();
}
/* Flip the authentication flag.*/
theAuthenticationFlag = true;
return;
}
public void pullDirectories()
{
if( theAuthenticationFlag )
{
String result, sender, subject, folderName;
String [] splitResult, senders, subjects;
/* If the all flag is set, all directories are polled. */
if(theAllFlag)
{
theFolders = getFullDirectoryList();
}
/* Create the directories for storing the emails. */
createDirectories();
int numEmails = 0;
int counter = 0; // Used to name the email folder
/*
* Iterate through all the given directories and create them if
* they don't already exist.
*/
for( String folder : theFolders )
{
/* Create the command string. */
String command = "$ SELECT " + folder + "\r\n";
try
{
sendCommand (command);
while((result = theInputBuffer.readLine()) != null) {
// Get the number of emails present in the mailbox
if (result.matches(".*\\bEXISTS\\b.*")) {
numEmails = Integer.parseInt (result.replaceAll("\\D+",""));
}
// Breaks out on success or failure
else if (result.matches(".*\\b(Success)\\b.*") ||
result.matches(".*\\b(Failure)\\b.*")) {
break;
}
}
senders = new String [numEmails];
subjects = new String [numEmails];
command = "$ FETCH 1:" + numEmails + " (FLAGS BODY[HEADER.FIELDS (From)])\r\n";
sendCommand (command);
// Loop to get all the results of the fetch command
for (int i = 0; i < numEmails; i++) {
while ((result = theInputBuffer.readLine()) != null) {
// Breaks out on success or failure, or parenthesis
if (result.matches(".*\\b(Success)\\b.*") ||
result.matches(".*\\b(Failure)\\b.*") ||
result.equals(")")) {
break;
}
// get the email between the angle brackets
if (result.contains("From")) {
sender = theInputBuffer.readLine();
sender = sender.split("<")[1].split(">")[0];
senders[i] = sender;
}
}
}
theInputBuffer.readLine(); // get last success message out
command = "$ FETCH 1:" + numEmails + " (FLAGS BODY[HEADER.FIELDS (Subject)])\r\n";
sendCommand (command);
for (int i = 0; i < numEmails; i++) {
while ((result = theInputBuffer.readLine()) != null) {
// Breaks out on success or failure
if (result.matches(".*\\b(Success)\\b.*") ||
result.matches(".*\\b(Failure)\\b.*") ||
result.equals(")")) {
break;
}
splitResult = result.split(":");
if (splitResult[0].equals("Subject")) {
subject = splitResult[1];
subject = subject.trim();
subject = subject.replaceAll("[^A-Za-z0-9]", "-");
subjects[i] = subject;
}
}
}
theInputBuffer.readLine(); // get last success message
command = "$ FETCH 1:" + numEmails + " BODY[TEXT]\r\n";
sendCommand (command);
// Create email folders within the mailbox
for (int i = 0; i < numEmails; i++) {
theInputBuffer.readLine(); // first line useless for our purposes
folderName = Integer.toString(counter++) + "_" + senders[i] + "_" + subjects[i];
new File (folder, folderName).mkdirs();
PrintWriter writer = new PrintWriter(new FileWriter(
folder + File.separator + folderName + File.separator + "content.txt"),
true);
while ((result = theInputBuffer.readLine()) != null) {
if (result.equals(")")) {
break;
}
writer.println (result);
}
}
if (deleteFlag) {
command = "$ DELETE " + folder + "\r\n";
sendCommand(command);
}
return;
} catch (IOException theException) {
theException.printStackTrace();
}
}
}
}
private String[] getFullDirectoryList()
{
ArrayList<String> output = new ArrayList<String>();
String result;
/* Regex variables. */
Pattern extractionPattern = Pattern.compile("(\")(([A-Z]).*?)(\")$");
Matcher extractionMatcher;
/* Build the list command. */
String listCommand = "$ LIST \"\" *\r\n" ;
/* Attempt to run the command and extract the result. */
try
{
theOutputStream.write(listCommand.getBytes());
theOutputStream.flush();
while((result = theInputBuffer.readLine()) != null)
{
if (result.matches(".*\\b(Success)\\b.*") ||
result.matches(".*\\b(Failure)\\b.*")) {
break;
}
// Check if matches no children before add.
else if(result.contains("HasNoChildren"))
{
// get rid of all characters that can be problematic in creating the folder
result = result.replaceAll("[^A-Za-z0-9\"\\/ ]", "");
System.out.println (result);
extractionMatcher = extractionPattern.matcher(result);
extractionMatcher.find();
result = extractionMatcher.group(2);
output.add(result);
}
}
}
catch (IOException inException) {
inException.printStackTrace();
}
return output.toArray(new String[output.size()]);
}
private void sendCommand (String command)
{
try
{
theOutputStream.write(command.getBytes());
theOutputStream.flush();
}
catch (IOException exception)
{
exception.printStackTrace();
}
}
private void createDirectories()
{
for( String folder : theFolders )
{
// Creates directories and any nested subdirectories
if(new File(folder).mkdirs())
{
System.out.println("Created directory ./" + folder);
}
else
{
System.out.println("Failed to create directory ./" + folder);
}
}
return;
}
////////////////////
// Nested Classes //
////////////////////
/**
* Nested event class used for socket handshake.
*/
class HandShakeListener implements HandshakeCompletedListener
{
private static final String DEF_HANDSHAKE_MSG = "Handshake Successful!";
@Override
public void handshakeCompleted( HandshakeCompletedEvent inEvent)
{
System.out.println( DEF_HANDSHAKE_MSG );
}
}
}
/********************************
*
* LEFTOVERS
*
*
*
System.out.println("The Certificates used by peer");
for (int i = 0; i < certChain.length; i++)
{
System.out.println(((X509Certificate) certChain[i]).getSubjectDN());
}
System.out.println("Peer host is " + session.getPeerHost());
System.out.println("Cipher is " + session.getCipherSuite());
System.out.println("Protocol is " + session.getProtocol());
System.out.println("ID is " + new BigInteger(session.getId()));
System.out.println("Session created in " + session.getCreationTime());
System.out.println("Session accessed in " + session.getLastAccessedTime());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String x = in.readLine();
System.out.println(x);
in.close();
*
*
*/