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.fetchmail;
23
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Enumeration;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32
33 import javax.mail.MessagingException;
34 import javax.mail.Session;
35
36 import org.apache.avalon.cornerstone.services.scheduler.Target;
37 import org.apache.avalon.framework.configuration.Configurable;
38 import org.apache.avalon.framework.configuration.Configuration;
39 import org.apache.avalon.framework.configuration.ConfigurationException;
40 import org.apache.avalon.framework.logger.AbstractLogEnabled;
41 import org.apache.avalon.framework.service.ServiceException;
42 import org.apache.avalon.framework.service.ServiceManager;
43 import org.apache.avalon.framework.service.Serviceable;
44 import org.apache.james.api.dnsservice.DNSService;
45 import org.apache.james.api.user.UsersRepository;
46 import org.apache.james.services.MailServer;
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 public class FetchMail extends AbstractLogEnabled implements Configurable, Target, Serviceable
78 {
79
80
81
82 private class DynamicAccountKey
83 {
84
85
86
87 private String fieldUserName;
88
89
90
91
92 private int fieldSequenceNumber;
93
94
95
96
97 private DynamicAccountKey()
98 {
99 super();
100 }
101
102
103
104
105 public DynamicAccountKey(String userName, int sequenceNumber)
106 {
107 this();
108 setUserName(userName);
109 setSequenceNumber(sequenceNumber);
110 }
111
112
113
114
115 public boolean equals(Object obj)
116 {
117 if (null == obj)
118 return false;
119 if (!(obj.getClass() == getClass()))
120 return false;
121 return (
122 getUserName().equals(((DynamicAccountKey) obj).getUserName())
123 && getSequenceNumber()
124 == ((DynamicAccountKey) obj).getSequenceNumber());
125 }
126
127
128
129
130 public int hashCode()
131 {
132 return getUserName().hashCode() ^ getSequenceNumber();
133 }
134
135
136
137
138
139 public int getSequenceNumber()
140 {
141 return fieldSequenceNumber;
142 }
143
144
145
146
147
148 public String getUserName()
149 {
150 return fieldUserName;
151 }
152
153
154
155
156
157 protected void setSequenceNumber(int sequenceNumber)
158 {
159 fieldSequenceNumber = sequenceNumber;
160 }
161
162
163
164
165
166 protected void setUserName(String userName)
167 {
168 fieldUserName = userName;
169 }
170
171 }
172
173
174
175 private class ParsedDynamicAccountParameters
176 {
177 private String fieldUserPrefix;
178 private String fieldUserSuffix;
179
180 private String fieldPassword;
181
182 private int fieldSequenceNumber;
183
184 private boolean fieldIgnoreRecipientHeader;
185 private String fieldRecipientPrefix;
186 private String fieldRecipientSuffix;
187 private String customRecipientHeader;
188
189
190
191
192 private ParsedDynamicAccountParameters()
193 {
194 super();
195 }
196
197
198
199
200 public ParsedDynamicAccountParameters(
201 int sequenceNumber,
202 Configuration configuration)
203 throws ConfigurationException
204 {
205 this();
206 setSequenceNumber(sequenceNumber);
207 setUserPrefix(configuration.getAttribute("userprefix", ""));
208 setUserSuffix(configuration.getAttribute("usersuffix", ""));
209 setRecipientPrefix(configuration.getAttribute("recipientprefix", ""));
210 setRecipientSuffix(configuration.getAttribute("recipientsuffix", ""));
211 setPassword(configuration.getAttribute("password"));
212 setIgnoreRecipientHeader(
213 configuration.getAttributeAsBoolean("ignorercpt-header"));
214 setCustomRecipientHeader(configuration.getAttribute("customrcpt-header", ""));
215 }
216
217
218
219
220
221 public String getCustomRecipientHeader() {
222 return this.customRecipientHeader;
223 }
224
225
226
227
228
229 public String getRecipientPrefix()
230 {
231 return fieldRecipientPrefix;
232 }
233
234
235
236
237
238 public String getRecipientSuffix()
239 {
240 return fieldRecipientSuffix;
241 }
242
243
244
245
246
247 public String getUserPrefix()
248 {
249 return fieldUserPrefix;
250 }
251
252
253
254
255
256 public String getUserSuffix()
257 {
258 return fieldUserSuffix;
259 }
260
261
262
263
264
265 public void setCustomRecipientHeader(String customRecipientHeader) {
266 this.customRecipientHeader = customRecipientHeader;
267 }
268
269
270
271
272
273 protected void setRecipientPrefix(String recipientprefix)
274 {
275 fieldRecipientPrefix = recipientprefix;
276 }
277
278
279
280
281
282 protected void setRecipientSuffix(String recipientsuffix)
283 {
284 fieldRecipientSuffix = recipientsuffix;
285 }
286
287
288
289
290
291 protected void setUserPrefix(String userprefix)
292 {
293 fieldUserPrefix = userprefix;
294 }
295
296
297
298
299
300 protected void setUserSuffix(String userSuffix)
301 {
302 fieldUserSuffix = userSuffix;
303 }
304
305
306
307
308
309 public String getPassword()
310 {
311 return fieldPassword;
312 }
313
314
315
316
317
318 protected void setIgnoreRecipientHeader(boolean ignoreRecipientHeader)
319 {
320 fieldIgnoreRecipientHeader = ignoreRecipientHeader;
321 }
322
323
324
325
326
327 protected void setPassword(String password)
328 {
329 fieldPassword = password;
330 }
331
332
333
334
335
336 public boolean isIgnoreRecipientHeader()
337 {
338 return fieldIgnoreRecipientHeader;
339 }
340
341
342
343
344
345 public int getSequenceNumber()
346 {
347 return fieldSequenceNumber;
348 }
349
350
351
352
353
354 protected void setSequenceNumber(int sequenceNumber)
355 {
356 fieldSequenceNumber = sequenceNumber;
357 }
358
359 }
360
361
362
363 private boolean fieldFetching = false;
364
365
366
367
368 private ParsedConfiguration fieldConfiguration;
369
370
371
372
373
374 private List fieldParsedDynamicAccountParameters;
375
376
377
378
379
380 private List fieldStaticAccounts;
381
382
383
384
385
386 private Session fieldSession;
387
388
389
390
391
392 private Map fieldDynamicAccounts;
393
394
395
396
397 private MailServer fieldServer;
398
399
400
401
402 private UsersRepository fieldLocalUsers;
403
404
405
406
407 private DNSService dnsServer;
408
409
410
411
412 public FetchMail()
413 {
414 super();
415 }
416
417
418
419
420
421
422
423
424
425 public void configure(Configuration configuration)
426 throws ConfigurationException
427 {
428
429 setSessionParameters(configuration);
430
431
432 ParsedConfiguration parsedConfiguration =
433 new ParsedConfiguration(
434 configuration,
435 getLogger(),
436 getServer(),
437 getLocalUsers(),
438 getDNSServer());
439 setConfiguration(parsedConfiguration);
440
441
442 Configuration[] allAccounts = configuration.getChildren("accounts");
443 if (allAccounts.length < 1)
444 throw new ConfigurationException("Missing <accounts> section.");
445 if (allAccounts.length > 1)
446 throw new ConfigurationException("Too many <accounts> sections, there must be exactly one");
447 Configuration accounts = allAccounts[0];
448
449
450 Configuration[] accountsChildren = accounts.getChildren();
451 if (accountsChildren.length < 1)
452 throw new ConfigurationException("Missing <account> section.");
453
454 for (int i = 0; i < accountsChildren.length; i++)
455 {
456 Configuration accountsChild = accountsChildren[i];
457
458 if ("alllocal".equals(accountsChild.getName()))
459 {
460
461
462 getParsedDynamicAccountParameters().add(
463 new ParsedDynamicAccountParameters(i, accountsChild));
464 continue;
465 }
466
467 if ("account".equals(accountsChild.getName()))
468 {
469
470
471 getStaticAccounts().add(
472 new Account(
473 i,
474 parsedConfiguration,
475 accountsChild.getAttribute("user"),
476 accountsChild.getAttribute("password"),
477 accountsChild.getAttribute("recipient"),
478 accountsChild.getAttributeAsBoolean(
479 "ignorercpt-header"),
480 accountsChild.getAttribute("customrcpt-header",""),
481 getSession()));
482 continue;
483 }
484
485 throw new ConfigurationException(
486 "Illegal token: <"
487 + accountsChild.getName()
488 + "> in <accounts>");
489 }
490 }
491
492
493
494
495
496
497 public void targetTriggered(String arg0)
498 {
499
500 if (isFetching())
501 {
502 getLogger().info(
503 "Triggered fetch cancelled. A fetch is already in progress.");
504 return;
505 }
506
507
508 try
509 {
510 setFetching(true);
511 getLogger().info("Fetcher starting fetches");
512
513
514
515 if (getLogger().isDebugEnabled())
516 {
517 getLogger().debug("Session properties:");
518 Properties properties = getSession().getProperties();
519 Enumeration e = properties.keys();
520 while (e.hasMoreElements())
521 {
522 String key = (String) e.nextElement();
523 String val = (String) properties.get(key);
524 if (val.length() > 40)
525 {
526 val = val.substring(0, 37) + "...";
527 }
528 getLogger().debug(key + "=" + val);
529
530 }
531 }
532
533
534
535
536
537 updateDynamicAccounts();
538 ArrayList mergedAccounts =
539 new ArrayList(
540 getDynamicAccounts().size() + getStaticAccounts().size());
541 mergedAccounts.addAll(getDynamicAccounts().values());
542 mergedAccounts.addAll(getStaticAccounts());
543 Collections.sort(mergedAccounts);
544
545 StringBuffer logMessage = new StringBuffer(64);
546 logMessage.append("Processing ");
547 logMessage.append(getStaticAccounts().size());
548 logMessage.append(" static accounts and ");
549 logMessage.append(getDynamicAccounts().size());
550 logMessage.append(" dynamic accounts.");
551 getLogger().info(logMessage.toString());
552
553
554 Iterator accounts = mergedAccounts.iterator();
555 while (accounts.hasNext())
556 {
557 try
558 {
559 new StoreProcessor((Account) accounts.next()).process();
560 }
561 catch (MessagingException ex)
562 {
563 getLogger().error(
564 "A MessagingException has terminated processing of this Account",
565 ex);
566 }
567 }
568 }
569 catch (Exception ex)
570 {
571 getLogger().error("An Exception has terminated this fetch.", ex);
572 }
573 finally
574 {
575 getLogger().info("Fetcher completed fetches");
576
577
578 setFetching(false);
579 }
580 }
581
582
583
584
585
586 protected boolean isFetching()
587 {
588 return fieldFetching;
589 }
590
591
592
593
594 public void service(final ServiceManager manager) throws ServiceException
595 {
596 try
597 {
598 setServer((MailServer) manager.lookup(MailServer.ROLE));
599 }
600 catch (ClassCastException cce)
601 {
602 StringBuffer errorBuffer =
603 new StringBuffer(128).append("Component ").append(
604 MailServer.ROLE).append(
605 "does not implement the required interface.");
606 throw new ServiceException("", errorBuffer.toString());
607 }
608
609 DNSService dnsServer = (DNSService) manager.lookup(DNSService.ROLE);
610 setDNSServer(dnsServer);
611
612 UsersRepository usersRepository =
613 (UsersRepository) manager.lookup(UsersRepository.ROLE);
614 setLocalUsers(usersRepository);
615 }
616
617
618
619
620
621
622
623
624
625
626 protected void setFetching(boolean fetching)
627 {
628 fieldFetching = fetching;
629 }
630
631
632
633
634
635 protected MailServer getServer()
636 {
637 return fieldServer;
638 }
639
640
641
642
643
644 protected ParsedConfiguration getConfiguration()
645 {
646 return fieldConfiguration;
647 }
648
649
650
651
652
653 protected void setConfiguration(ParsedConfiguration configuration)
654 {
655 fieldConfiguration = configuration;
656 }
657
658
659
660
661
662 protected void setServer(MailServer server)
663 {
664 fieldServer = server;
665 }
666
667
668
669
670
671 protected UsersRepository getLocalUsers()
672 {
673 return fieldLocalUsers;
674 }
675
676
677
678
679
680 protected void setLocalUsers(UsersRepository localUsers)
681 {
682 fieldLocalUsers = localUsers;
683 }
684
685
686
687
688
689 protected DNSService getDNSServer()
690 {
691 return dnsServer;
692 }
693
694
695
696
697
698 protected void setDNSServer(DNSService dnsServer)
699 {
700 this.dnsServer = dnsServer;
701 }
702
703
704
705
706
707
708 protected List getStaticAccounts()
709 {
710 if (null == getStaticAccountsBasic())
711 {
712 updateStaticAccounts();
713 return getStaticAccounts();
714 }
715 return fieldStaticAccounts;
716 }
717
718
719
720
721
722 private List getStaticAccountsBasic()
723 {
724 return fieldStaticAccounts;
725 }
726
727
728
729
730
731 protected void setStaticAccounts(List accounts)
732 {
733 fieldStaticAccounts = accounts;
734 }
735
736
737
738
739 protected void updateStaticAccounts()
740 {
741 setStaticAccounts(computeStaticAccounts());
742 }
743
744
745
746
747 protected void updateParsedDynamicAccountParameters()
748 {
749 setParsedDynamicAccountParameters(computeParsedDynamicAccountParameters());
750 }
751
752
753
754
755 protected void updateDynamicAccounts() throws ConfigurationException
756 {
757 setDynamicAccounts(computeDynamicAccounts());
758 }
759
760
761
762
763 protected List computeStaticAccounts()
764 {
765 return new ArrayList();
766 }
767
768
769
770
771 protected List computeParsedDynamicAccountParameters()
772 {
773 return new ArrayList();
774 }
775
776
777
778
779 protected Map computeDynamicAccounts() throws ConfigurationException
780 {
781 Map newAccounts =
782 new HashMap(
783 getLocalUsers().countUsers()
784 * getParsedDynamicAccountParameters().size());
785 Map oldAccounts = getDynamicAccountsBasic();
786 if (null == oldAccounts)
787 oldAccounts = new HashMap(0);
788
789 Iterator parameterIterator =
790 getParsedDynamicAccountParameters().iterator();
791
792
793 while (parameterIterator.hasNext())
794 {
795 Map accounts =
796 computeDynamicAccounts(
797 oldAccounts,
798 (ParsedDynamicAccountParameters) parameterIterator.next());
799
800
801
802 Iterator oldAccountsIterator = oldAccounts.keySet().iterator();
803 while (oldAccountsIterator.hasNext())
804 {
805 if (accounts.containsKey(oldAccountsIterator.next()))
806 oldAccountsIterator.remove();
807 }
808
809 newAccounts.putAll(accounts);
810 }
811 return newAccounts;
812 }
813
814
815
816
817
818 protected Map getDynamicAccounts() throws ConfigurationException
819 {
820 if (null == getDynamicAccountsBasic())
821 {
822 updateDynamicAccounts();
823 return getDynamicAccounts();
824 }
825 return fieldDynamicAccounts;
826 }
827
828
829
830
831
832 private Map getDynamicAccountsBasic()
833 {
834 return fieldDynamicAccounts;
835 }
836
837
838
839
840
841 protected void setDynamicAccounts(Map dynamicAccounts)
842 {
843 fieldDynamicAccounts = dynamicAccounts;
844 }
845
846
847
848
849
850
851
852
853
854
855 protected Map computeDynamicAccounts(
856 Map oldAccounts,
857 ParsedDynamicAccountParameters parameters)
858 throws ConfigurationException
859 {
860 Map accounts = new HashMap(getLocalUsers().countUsers());
861 Iterator usersIterator = getLocalUsers().list();
862 while (usersIterator.hasNext())
863 {
864 String userName = (String) usersIterator.next();
865 DynamicAccountKey key =
866 new DynamicAccountKey(userName, parameters.getSequenceNumber());
867 Account account = (Account) oldAccounts.get(key);
868 if (null == account)
869 {
870
871 account =
872 new DynamicAccount(
873 parameters.getSequenceNumber(),
874 getConfiguration(),
875 userName,
876 parameters.getUserPrefix(),
877 parameters.getUserSuffix(),
878 parameters.getPassword(),
879 parameters.getRecipientPrefix(),
880 parameters.getRecipientSuffix(),
881 parameters.isIgnoreRecipientHeader(),
882 parameters.getCustomRecipientHeader(),
883 getSession());
884 }
885 accounts.put(key, account);
886 }
887 return accounts;
888 }
889
890
891
892
893 protected void resetDynamicAccounts()
894 {
895 setDynamicAccounts(null);
896 }
897
898
899
900
901
902 protected List getParsedDynamicAccountParameters()
903 {
904 if (null == getParsedDynamicAccountParametersBasic())
905 {
906 updateParsedDynamicAccountParameters();
907 return getParsedDynamicAccountParameters();
908 }
909 return fieldParsedDynamicAccountParameters;
910 }
911
912
913
914
915
916 private List getParsedDynamicAccountParametersBasic()
917 {
918 return fieldParsedDynamicAccountParameters;
919 }
920
921
922
923
924
925 protected void setParsedDynamicAccountParameters(List parsedDynamicAccountParameters)
926 {
927 fieldParsedDynamicAccountParameters = parsedDynamicAccountParameters;
928 }
929
930
931
932
933
934 protected Session getSession()
935 {
936 Session session = null;
937 if (null == (session = getSessionBasic()))
938 {
939 updateSession();
940 return getSession();
941 }
942 return session;
943 }
944
945
946
947
948
949 private Session getSessionBasic()
950 {
951 return fieldSession;
952 }
953
954
955
956
957
958 protected Session computeSession()
959 {
960 return Session.getInstance(System.getProperties());
961 }
962
963
964
965
966 protected void updateSession()
967 {
968 setSession(computeSession());
969 }
970
971
972
973
974
975 protected void setSession(Session session)
976 {
977 fieldSession = session;
978 }
979
980
981
982
983
984
985
986 protected void setSessionParameters(Configuration configuration)
987 throws ConfigurationException
988 {
989 Configuration javaMailProperties =
990 configuration.getChild("javaMailProperties", false);
991 if (null != javaMailProperties)
992 {
993 Properties properties = getSession().getProperties();
994 Configuration[] allProperties =
995 javaMailProperties.getChildren("property");
996 for (int i = 0; i < allProperties.length; i++)
997 {
998 properties.setProperty(
999 allProperties[i].getAttribute("name"),
1000 allProperties[i].getAttribute("value"));
1001 if (getLogger().isDebugEnabled())
1002 {
1003 StringBuffer messageBuffer =
1004 new StringBuffer("Set property name: ");
1005 messageBuffer.append(allProperties[i].getAttribute("name"));
1006 messageBuffer.append(" to: ");
1007 messageBuffer.append(
1008 allProperties[i].getAttribute("value"));
1009 getLogger().debug(messageBuffer.toString());
1010 }
1011 }
1012 }
1013 }
1014
1015 }