1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.james.core;
23
24 import org.apache.avalon.framework.activity.Disposable;
25 import org.apache.avalon.framework.container.ContainerUtil;
26 import org.apache.mailet.Mail;
27 import org.apache.mailet.MailAddress;
28 import org.apache.mailet.base.RFC2822Headers;
29
30 import javax.mail.MessagingException;
31 import javax.mail.internet.InternetAddress;
32 import javax.mail.internet.MimeMessage;
33 import javax.mail.internet.ParseException;
34
35 import java.io.ByteArrayInputStream;
36 import java.io.ByteArrayOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.ObjectInputStream;
40 import java.io.ObjectOutputStream;
41 import java.io.OptionalDataException;
42 import java.io.OutputStream;
43 import java.io.Serializable;
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.Date;
47 import java.util.HashMap;
48 import java.util.Iterator;
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class MailImpl implements Disposable, Mail {
63
64
65
66
67
68 public static final long serialVersionUID = -4289663364703986260L;
69
70
71
72 private String errorMessage;
73
74
75
76 private String state;
77
78
79
80 private MimeMessage message;
81
82
83
84 private MailAddress sender;
85
86
87
88 private Collection recipients;
89
90
91
92 private String name;
93
94
95
96 private String remoteHost = "localhost";
97
98
99
100 private String remoteAddr = "127.0.0.1";
101
102
103
104 private Date lastUpdated = new Date();
105
106
107
108 private HashMap attributes;
109
110
111
112 public MailImpl() {
113 setState(Mail.DEFAULT);
114 attributes = new HashMap();
115 }
116
117
118
119
120
121
122
123
124 public MailImpl(String name, MailAddress sender, Collection recipients) {
125 this();
126 this.name = name;
127 this.sender = sender;
128 this.recipients = null;
129
130
131 if (recipients != null) {
132 Iterator theIterator = recipients.iterator();
133 this.recipients = new ArrayList();
134 while (theIterator.hasNext()) {
135 this.recipients.add(theIterator.next());
136 }
137 }
138 }
139
140
141
142
143
144
145
146 public MailImpl(Mail mail) throws MessagingException {
147 this(mail, newName(mail));
148 }
149
150
151
152
153
154
155 public MailImpl(Mail mail, String newName) throws MessagingException {
156 this(newName, mail.getSender(), mail.getRecipients(), mail.getMessage());
157 setRemoteHost(mail.getRemoteHost());
158 setRemoteAddr(mail.getRemoteAddr());
159 setLastUpdated(mail.getLastUpdated());
160 try {
161 if (mail instanceof MailImpl) {
162 setAttributesRaw((HashMap) cloneSerializableObject(((MailImpl) mail).getAttributesRaw()));
163 } else {
164 HashMap attribs = new HashMap();
165 for (Iterator i = mail.getAttributeNames(); i.hasNext(); ) {
166 String hashKey = (String) i.next();
167 attribs.put(hashKey,cloneSerializableObject(mail.getAttribute(hashKey)));
168 }
169 setAttributesRaw(attribs);
170 }
171 } catch (IOException e) {
172
173 setAttributesRaw(new HashMap());
174 } catch (ClassNotFoundException e) {
175
176 setAttributesRaw(new HashMap());
177 }
178 }
179
180
181
182
183
184
185
186
187
188
189 public MailImpl(String name, MailAddress sender, Collection recipients, InputStream messageIn)
190 throws MessagingException {
191 this(name, sender, recipients);
192 MimeMessageSource source = new MimeMessageInputStreamSource(name, messageIn);
193
194
195 try {
196 this.setMessage(new MimeMessageCopyOnWriteProxy(source));
197 } catch (MessagingException e) {
198 ContainerUtil.dispose(source);
199 throw e;
200 }
201 }
202
203
204
205
206
207
208
209
210
211
212 public MailImpl(String name, MailAddress sender, Collection recipients, MimeMessage message) throws MessagingException {
213 this(name, sender, recipients);
214 this.setMessage(new MimeMessageCopyOnWriteProxy(message));
215 }
216
217
218
219
220
221
222 private MailAddress getReturnPath(MimeMessage message) throws MessagingException {
223 MailAddress mailAddress = null;
224 String[] returnPathHeaders = message.getHeader(RFC2822Headers.RETURN_PATH);
225 String returnPathHeader = null;
226 if (returnPathHeaders != null) {
227 returnPathHeader = returnPathHeaders[0];
228 if (returnPathHeader != null) {
229 returnPathHeader = returnPathHeader.trim();
230 if (!returnPathHeader.equals("<>")) {
231 try {
232 mailAddress = new MailAddress(new InternetAddress(returnPathHeader, false));
233 } catch (ParseException pe) {
234 throw new MessagingException("Could not parse address: " + returnPathHeader + " from " + message.getHeader(RFC2822Headers.RETURN_PATH, ", "), pe);
235 }
236 }
237 }
238 }
239 return mailAddress;
240 }
241
242
243
244
245
246 public Mail duplicate() {
247 return duplicate(name);
248 }
249
250
251
252
253
254
255
256
257 public Mail duplicate(String newName) {
258 try {
259 return new MailImpl(this, newName);
260 } catch (MessagingException me) {
261
262 }
263 return null;
264 }
265
266
267
268
269
270 public String getErrorMessage() {
271 return errorMessage;
272 }
273
274
275
276
277
278 public MimeMessage getMessage() throws MessagingException {
279 return message;
280 }
281
282
283
284
285
286
287 public void setName(String name) {
288 this.name = name;
289 }
290
291
292
293
294
295 public String getName() {
296 return name;
297 }
298
299
300
301
302
303 public Collection getRecipients() {
304 return recipients;
305 }
306
307
308
309
310
311 public MailAddress getSender() {
312 return sender;
313 }
314
315
316
317
318
319 public String getState() {
320 return state;
321 }
322
323
324
325
326
327 public String getRemoteHost() {
328 return remoteHost;
329 }
330
331
332
333
334
335 public String getRemoteAddr() {
336 return remoteAddr;
337 }
338
339
340
341
342
343 public Date getLastUpdated() {
344 return lastUpdated;
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359 public long getMessageSize() throws MessagingException {
360 return MimeMessageUtil.getMessageSize(message);
361 }
362
363
364
365
366
367
368 public void setErrorMessage(String msg) {
369 this.errorMessage = msg;
370 }
371
372
373
374
375
376 public void setMessage(MimeMessage message) {
377
378
379
380
381
382 if (this.message != message) {
383
384
385
386 if (this.message != null) {
387 ContainerUtil.dispose(this.message);
388 }
389 this.message = message;
390 }
391 }
392
393
394
395
396
397 public void setRecipients(Collection recipients) {
398 this.recipients = recipients;
399 }
400
401
402
403
404
405 public void setSender(MailAddress sender) {
406 this.sender = sender;
407 }
408
409
410
411
412
413 public void setState(String state) {
414 this.state = state;
415 }
416
417
418
419
420
421 public void setRemoteHost(String remoteHost) {
422 this.remoteHost = remoteHost;
423 }
424
425
426
427
428
429 public void setRemoteAddr(String remoteAddr) {
430 this.remoteAddr = remoteAddr;
431 }
432
433
434
435
436
437 public void setLastUpdated(Date lastUpdated) {
438
439
440 if (lastUpdated != null) {
441 lastUpdated = new Date(lastUpdated.getTime());
442 }
443 this.lastUpdated = lastUpdated;
444 }
445
446
447
448
449
450
451
452
453 public void writeMessageTo(OutputStream out) throws IOException, MessagingException {
454 if (message != null) {
455 message.writeTo(out);
456 } else {
457 throw new MessagingException("No message set for this MailImpl.");
458 }
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473 private void readObject(java.io.ObjectInputStream in)
474 throws IOException, ClassNotFoundException {
475 try {
476 Object obj = in.readObject();
477 if (obj == null) {
478 sender = null;
479 } else if (obj instanceof String) {
480 sender = new MailAddress((String) obj);
481 } else if (obj instanceof MailAddress) {
482 sender = (MailAddress) obj;
483 }
484 } catch (ParseException pe) {
485 throw new IOException("Error parsing sender address: " + pe.getMessage());
486 }
487 recipients = (Collection) in.readObject();
488 state = (String) in.readObject();
489 errorMessage = (String) in.readObject();
490 name = (String) in.readObject();
491 remoteHost = (String) in.readObject();
492 remoteAddr = (String) in.readObject();
493 setLastUpdated((Date) in.readObject());
494
495
496 try {
497 attributes = (HashMap) in.readObject();
498 } catch (OptionalDataException ode) {
499 if (ode.eof) {
500 attributes = new HashMap();
501 } else {
502 throw ode;
503 }
504 }
505 }
506
507
508
509
510
511
512
513 private void writeObject(java.io.ObjectOutputStream out) throws IOException {
514 out.writeObject(sender);
515 out.writeObject(recipients);
516 out.writeObject(state);
517 out.writeObject(errorMessage);
518 out.writeObject(name);
519 out.writeObject(remoteHost);
520 out.writeObject(remoteAddr);
521 out.writeObject(lastUpdated);
522 out.writeObject(attributes);
523 }
524
525
526
527
528 public void dispose() {
529 ContainerUtil.dispose(message);
530 message = null;
531 }
532
533
534
535
536
537
538
539
540
541 public HashMap getAttributesRaw () {
542 return attributes;
543 }
544
545
546
547
548
549
550
551
552
553 public void setAttributesRaw (HashMap attr)
554 {
555 this.attributes = (attr == null) ? new HashMap() : attr;
556 }
557
558
559
560
561
562 public Serializable getAttribute(String key) {
563 return (Serializable)attributes.get(key);
564 }
565
566
567
568
569 public Serializable setAttribute(String key, Serializable object) {
570 return (Serializable)attributes.put(key, object);
571 }
572
573
574
575
576 public Serializable removeAttribute(String key) {
577 return (Serializable)attributes.remove(key);
578 }
579
580
581
582
583 public void removeAllAttributes() {
584 attributes.clear();
585 }
586
587
588
589
590 public Iterator getAttributeNames() {
591 return attributes.keySet().iterator();
592 }
593
594
595
596
597 public boolean hasAttributes() {
598 return !attributes.isEmpty();
599 }
600
601
602
603
604
605
606
607
608
609
610
611 private static Object cloneSerializableObject(Object o) throws IOException, ClassNotFoundException {
612 ByteArrayOutputStream b = new ByteArrayOutputStream();
613 ObjectOutputStream out = new ObjectOutputStream(b);
614 out.writeObject(o);
615 out.flush();
616 out.close();
617 ByteArrayInputStream bi=new ByteArrayInputStream(b.toByteArray());
618 ObjectInputStream in = new ObjectInputStream(bi);
619 Object no = in.readObject();
620 return no;
621 }
622
623
624 private static final java.util.Random random = new java.util.Random();
625
626
627
628
629
630
631
632 public static String newName(Mail mail) throws MessagingException {
633 String oldName = mail.getName();
634
635
636
637
638
639 if (oldName.length() > 76) {
640 int count = 0;
641 int index = 0;
642 while ((index = oldName.indexOf('!', index + 1)) >= 0) {
643 count++;
644 }
645
646 if (count > 7) {
647 throw new MessagingException("Unable to create a new message name: too long."
648 + " Possible loop in config.xml.");
649 }
650 else {
651 oldName = oldName.substring(0, 76);
652 }
653 }
654
655 StringBuffer nameBuffer =
656 new StringBuffer(64)
657 .append(oldName)
658 .append("-!")
659 .append(random.nextInt(1048576));
660 return nameBuffer.toString();
661 }
662
663 }