1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.mercury.common;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Properties;
25
26 import javax.mail.Folder;
27 import javax.mail.MessagingException;
28 import javax.mail.NoSuchProviderException;
29 import javax.mail.PasswordAuthentication;
30 import javax.mail.Session;
31 import javax.mail.Store;
32 import javax.mail.URLName;
33
34 import org.abstracthorizon.danube.support.RuntimeIOException;
35 import org.abstracthorizon.mercury.common.exception.UnknownUserException;
36 import org.abstracthorizon.mercury.common.exception.UserRejectedException;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
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 public class SimpleStorageManager implements StorageManager {
73
74
75 protected boolean caseSensitive = false;
76
77
78 protected Properties props = new Properties();
79
80
81 protected Session session;
82
83
84 protected File propertiesFile;
85
86
87 protected boolean autosave = true;
88
89
90 protected static final Logger logger = LoggerFactory.getLogger(SimpleStorageManager.class);
91
92
93
94
95 public SimpleStorageManager() {
96 }
97
98
99
100
101
102 public void setPropertiesFile(File propertiesFile) {
103 this.propertiesFile = propertiesFile;
104 }
105
106
107
108
109
110 public File getPropertiesFile() {
111 return propertiesFile;
112 }
113
114
115
116
117
118
119 public void setAutosave(boolean autosave) {
120 this.autosave = autosave;
121 }
122
123
124
125
126
127
128 public boolean isAutosave() {
129 return autosave;
130 }
131
132
133
134
135
136
137 public void setCaseSensitive(boolean caseSensitive) {
138 this.caseSensitive = caseSensitive;
139 if (!caseSensitive) {
140 toLowerCase();
141 }
142 }
143
144
145
146
147
148
149 public boolean isCaseSensitive() {
150 return caseSensitive;
151 }
152
153
154
155
156
157 public Session getJavaMailSession() {
158 return session;
159 }
160
161
162
163
164
165 public void setJavaMailSession(Session session) {
166 this.session = session;
167 }
168
169
170
171
172
173
174 public void init() throws IOException {
175 load();
176 if (session == null) {
177 session = Session.getDefaultInstance(new Properties());
178 }
179 }
180
181
182
183
184
185 public void load() throws IOException {
186 InputStream fis = getPropertiesInputStream();
187 try {
188 props.load(fis);
189 } finally {
190 fis.close();
191 }
192 if (!caseSensitive) {
193 toLowerCase();
194 }
195 }
196
197
198
199
200
201 public void save() {
202 try {
203 OutputStream fos = getPropertiesOutputStream();
204 if (fos != null) {
205 try {
206 props.store(fos, "# SMTP Manager data");
207 } finally {
208 fos.close();
209 }
210 }
211 } catch (IOException e) {
212 throw new RuntimeIOException(e);
213 }
214 }
215
216
217
218
219
220
221 protected InputStream getPropertiesInputStream() throws IOException {
222 return new FileInputStream(propertiesFile);
223 }
224
225
226
227
228
229
230 protected OutputStream getPropertiesOutputStream() throws IOException {
231 return new FileOutputStream(propertiesFile);
232 }
233
234
235
236
237
238 public String getMainDomain() {
239 return props.getProperty("server.domain");
240 }
241
242
243
244
245
246 public void setMainDomain(String domain) {
247 props.setProperty("server.domain", domain);
248 }
249
250
251
252
253
254 public boolean hasDomain(String domain) {
255 if (!caseSensitive) {
256 domain = domain.toLowerCase();
257 }
258 if (domain.equals(getMainDomain())) {
259 return true;
260 }
261 return props.getProperty("-@" + domain) != null;
262 }
263
264
265 public Store findStore(String mailbox, String domain, char[] password) throws UserRejectedException, MessagingException {
266
267 Folder folder = findInbox(mailbox, domain, password);
268 return folder.getStore();
269 }
270
271
272
273
274
275
276
277
278
279 public Folder findInbox(String mailbox, String domain, char[] password) throws UserRejectedException, MessagingException {
280 if (domain == null) {
281 domain = getMainDomain();
282 }
283 if (!caseSensitive) {
284 mailbox = mailbox.toLowerCase();
285 if (domain != null) {
286 domain = domain.toLowerCase();
287 }
288 }
289
290 String storeString = obtainStoreString(mailbox, domain);
291 if (storeString != null) {
292 URLName urlName = null;
293 if (password != null) {
294 urlName = createURLName(mailbox, new String(password), storeString);
295 } else {
296 urlName = createURLName(mailbox, null, storeString);
297 }
298
299 try {
300 if (password != null) {
301 PasswordAuthentication auth = new PasswordAuthentication(mailbox, new String(password));
302 session.setPasswordAuthentication(urlName, auth);
303 }
304 Store store = obtainStore(urlName);
305
306 store.connect();
307
308 String ref = urlName.getRef();
309 if (ref != null) {
310 return store.getFolder(ref);
311 } else {
312 return store.getFolder("INBOX");
313 }
314 } catch (NoSuchProviderException e) {
315
316
317 if (!mailbox.equals("postmaster") && (props.getProperty("-" + makeEntry("postmaster", domain)) != null)) {
318 return findInbox("postmaster", domain, null);
319 } else {
320 throw new UnknownUserException("User: " + makeEntry(mailbox, domain) + " now known", e);
321 }
322 }
323 }
324
325 throw new UnknownUserException("User: " + makeEntry(mailbox, domain) + " now known");
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 protected String obtainStoreString(String mailbox, String domain) throws MessagingException {
369
370 String storeString = null;
371 String mb = mailbox;
372 String dn = domain;
373 if (dn == null) {
374 dn = "";
375 }
376
377 String map = props.getProperty("-" + makeEntry(mb, dn));
378 if (map == null) {
379 map = props.getProperty("-" + makeEntry("", dn));
380 }
381 while ((map != null) && (storeString == null)) {
382 if (map.startsWith("S=")) {
383 storeString = map.substring(2);
384 storeString = decorateStoreString(mb, dn, storeString);
385 } else if (map.startsWith("A=")) {
386 int i = map.indexOf('@');
387 if (i >= 0) {
388 String t = map.substring(2, i);
389 if (t.length() > 0) {
390 mb = t;
391 }
392 dn = map.substring(i+1);
393 } else {
394 throw new MessagingException("Configuration error; expecting '@' in map='" + map + "'");
395 }
396 } else{
397 mb = "";
398 dn = "";
399 }
400
401 map = props.getProperty("-" + makeEntry(mb, dn));
402 if (map == null) {
403 map = props.getProperty("-" + makeEntry("", dn));
404 }
405 }
406 return storeString;
407 }
408
409 protected String decorateStoreString(String mailbox, String domain, String storeString) {
410 return storeString;
411 }
412
413 protected Store obtainStore(URLName urlName) throws MessagingException {
414
415
416
417 Store store = session.getStore(urlName);
418 return store;
419 }
420
421 protected URLName createURLName(String username, String password, String storeString) {
422 URLName urlName = new URLName(storeString);
423
424 urlName = new URLName(urlName.getProtocol(), urlName.getHost(), urlName.getPort(), urlName.getRef() == null ? urlName.getFile() : urlName.getFile() + "#" + urlName.getRef(), username, password);
425 return urlName;
426 }
427
428
429
430
431
432
433
434
435 public void addMailbox(String mailbox, String store) {
436 if (!caseSensitive) {
437 mailbox = mailbox.toLowerCase();
438 }
439 props.setProperty("-" + mailbox, "S=" + store);
440 if (autosave) { save(); }
441 }
442
443
444
445
446
447
448
449 public void addAlias(String mailbox, String destMailbox) throws IOException {
450 if (!caseSensitive) {
451 mailbox = mailbox.toLowerCase();
452 }
453 props.setProperty("-"+mailbox, "A="+destMailbox);
454 if (autosave) { save(); }
455 }
456
457
458
459
460
461 public void removeAlias(String mailbox) {
462 if (!caseSensitive) {
463 mailbox = mailbox.toLowerCase();
464 }
465 String property = props.getProperty("-" + mailbox);
466 if ((property != null) && property.startsWith("A=")) {
467 props.remove("-" + mailbox);
468 }
469 }
470
471
472
473
474
475
476 public void addDomain(String domain) {
477 if (!caseSensitive) {
478 domain = domain.toLowerCase();
479 }
480 if (props.getProperty("-" + makeEntry("", domain)) == null) {
481 props.setProperty("-" + makeEntry("", domain), "R");
482 if (autosave) { save(); }
483 }
484 }
485
486
487
488
489
490
491
492
493 public void addEntry(String mailbox, String entry) throws IOException {
494 if (!caseSensitive) {
495 mailbox = mailbox.toLowerCase();
496 }
497 props.setProperty("-"+mailbox, entry);
498 if (autosave) { save(); }
499 }
500
501
502
503
504
505
506 public boolean removeMailbox(String mailbox, String domain) {
507 boolean res = (props.remove("-" + makeEntry(mailbox, domain)) != null);
508
509 if (autosave) { save(); }
510 return res;
511 }
512
513
514
515
516
517
518 public boolean removeDomain(String domain) {
519 boolean res = (props.remove("-" + makeEntry("", domain)) != null);
520 if (autosave) { save(); }
521 return res;
522 }
523
524
525
526
527
528 public String[] getDomains() {
529 List<String> list = new ArrayList<String>();
530 Iterator<Object> it = props.keySet().iterator();
531 while (it.hasNext()) {
532 String s = (String)it.next();
533 if (s.startsWith("-@")) {
534 list.add(s.substring(2));
535 }
536 }
537 String[] res = new String[list.size()];
538 return list.toArray(res);
539 }
540
541
542
543
544
545 public String[] getMailboxNames() {
546 List<String> list = new ArrayList<String>();
547 Iterator<Object> it = props.keySet().iterator();
548 while (it.hasNext()) {
549 String s = (String)it.next();
550 if (s.startsWith("-")) {
551 String e = props.getProperty(s);
552 if (e.startsWith("S=")) {
553 int i = s.indexOf('@');
554 if (i >= 1) {
555 s = s.substring(1, i);
556 } else {
557 s = s.substring(1);
558 }
559 list.add(s);
560 }
561 }
562 }
563 String[] res = new String[list.size()];
564 return list.toArray(res);
565 }
566
567
568
569
570
571
572 public String[] getMailboxNames(String domain) {
573 List<String> list = new ArrayList<String>();
574 Iterator<Object> it = props.keySet().iterator();
575 while (it.hasNext()) {
576 String s = (String)it.next();
577 if (s.startsWith("-")) {
578 String e = props.getProperty(s);
579 if (e.startsWith("S=")) {
580 String d = "";
581 int i = s.indexOf('@');
582 if (i >= 1) {
583 d = s.substring(i+1);
584 s = s.substring(1, i);
585 } else {
586 s = s.substring(1);
587 }
588 if (domain.equals(d)) {
589 list.add(s);
590 }
591 }
592 }
593 }
594 String[] res = new String[list.size()];
595 return list.toArray(res);
596 }
597
598
599
600
601
602 public String[] getAliases() {
603 List<String> list = new ArrayList<String>();
604 Iterator<Object> it = props.keySet().iterator();
605 while (it.hasNext()) {
606 String s = (String)it.next();
607 if (s.startsWith("-")) {
608 String e = props.getProperty(s);
609 if (e.startsWith("A=")) {
610 list.add(s.substring(1)+"="+e.substring(2));
611 }
612 }
613 }
614 String[] res = new String[list.size()];
615 return list.toArray(res);
616 }
617
618
619
620
621 protected void toLowerCase() {
622 ArrayList<Entry> changes = new ArrayList<Entry>();
623 Iterator<Object> it = props.keySet().iterator();
624 while (it.hasNext()) {
625 String key = (String)it.next();
626 String lowerCaseKey = key.toLowerCase();
627 if (!lowerCaseKey.equals(key) && (props.getProperty(lowerCaseKey) == null)) {
628 String value = props.getProperty(key);
629 it.remove();
630 changes.add(new Entry(lowerCaseKey, value));
631 }
632 }
633 Iterator<Entry> it2 = changes.iterator();
634 while (it2.hasNext()) {
635 Entry entry = it2.next();
636 props.setProperty(entry.key, entry.value);
637 }
638 }
639
640 protected String makeEntry(String mailbox, String domain) {
641 if (domain != null) {
642 return mailbox + "@" + domain;
643 } else {
644 return mailbox + "@";
645 }
646 }
647
648
649
650
651 protected static class Entry {
652 protected String key;
653 protected String value;
654 public Entry(String key, String value) {
655 this.key = key;
656 this.value = value;
657 }
658 }
659
660
661
662
663 protected static class URLNameFix extends URLName {
664
665
666
667
668
669
670 public URLNameFix(URLName urlName, String username) {
671 super(urlName.getProtocol(), urlName.getHost(), urlName.getPort(), urlName.getRef() == null ? urlName.getFile() : urlName.getFile() + "#" + urlName.getRef(), username, null);
672 }
673
674
675
676
677
678 public String getFile() {
679 String file = super.getFile();
680 String ref = super.getRef();
681 if (ref == null) {
682 return file;
683 } else {
684 return file + "#" + ref;
685 }
686 }
687
688 }
689 }