View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2009  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  package davmail;
20  
21  import davmail.caldav.CaldavServer;
22  import davmail.exception.DavMailException;
23  import davmail.exchange.ExchangeSessionFactory;
24  import davmail.exchange.auth.ExchangeAuthenticator;
25  import davmail.exchange.auth.KerberosCheck;
26  import davmail.http.HttpClientAdapter;
27  import davmail.http.request.GetRequest;
28  import davmail.http.SelfSignedCertificateGenerator;
29  import davmail.imap.ImapServer;
30  import davmail.ldap.LdapServer;
31  import davmail.pop.PopServer;
32  import davmail.smtp.SmtpServer;
33  import davmail.ui.tray.DavGatewayTray;
34  import org.apache.log4j.Logger;
35  
36  import java.awt.*;
37  import java.io.IOException;
38  import java.lang.reflect.InvocationTargetException;
39  import java.util.ArrayList;
40  
41  /**
42   * DavGateway main class
43   */
44  public final class DavGateway {
45      private static final Logger LOGGER = Logger.getLogger(DavGateway.class);
46      private static final String HTTP_DAVMAIL_SOURCEFORGE_NET_VERSION_TXT = "https://davmail.sourceforge.net/version.txt";
47  
48      private static final Object LOCK = new Object();
49      private static boolean shutdown = false;
50  
51      private DavGateway() {
52      }
53  
54      private static final ArrayList<AbstractServer> SERVER_LIST = new ArrayList<>();
55  
56      /**
57       * Start the gateway, listen on specified smtp and pop3 ports
58       *
59       * @param args command line parameter config file path
60       */
61      public static void main(String[] args) {
62          boolean noTray = false;
63          boolean tray = false;
64          boolean server = false;
65          boolean token = false;
66          boolean kerberos = false;
67          boolean generateCert = false;
68  
69          // check environment for davmail settings path in Docker
70          String configFilePath = Settings.getConfigFilePath();
71          for (int i = 0; i < args.length; i++) {
72              String arg = args[i];
73              if (arg.startsWith("-")) {
74                  switch (arg) {
75                      case "-notray":
76                          noTray = true;
77                          break;
78                      case "-tray":
79                          tray = true;
80                          break;
81                      case "-server":
82                          server = true;
83                          break;
84                      case "-token":
85                          token = true;
86                          break;
87                      case "-kerberos":
88                          kerberos = true;
89                          break;
90                      case "-generateCert":
91                          generateCert = true;
92                          break;
93                      default:
94                          LOGGER.warn("Unknown option: " + arg);
95                  }
96              } else {
97                  configFilePath = arg;
98              }
99          }
100 
101         Settings.setConfigFilePath(configFilePath);
102         Settings.load();
103 
104         // use notray / tray to override davmail.enableTray
105         if (tray) {
106             Settings.setProperty("davmail.enableTray", "true");
107         }
108         if (noTray) {
109             Settings.setProperty("davmail.enableTray", "false");
110         }
111 
112         if (generateCert) {
113             SelfSignedCertificateGenerator.generate(configFilePath);
114             System.exit(0);
115         } else if (token) {
116             try {
117                 ExchangeAuthenticator authenticator = (ExchangeAuthenticator) Class.forName("davmail.exchange.auth.O365InteractiveAuthenticator")
118                         .getDeclaredConstructor().newInstance();
119                 authenticator.setUsername("");
120                 authenticator.authenticate();
121                 System.out.println(authenticator.getToken().getRefreshToken());
122             } catch (IOException | ClassNotFoundException | NoSuchMethodException | InstantiationException |
123                      IllegalAccessException | InvocationTargetException e) {
124                 System.err.println(e + " " + e.getMessage());
125             }
126             // force shutdown on Linux
127             System.exit(0);
128         } else if (kerberos) {
129             KerberosCheck kerberosCheck = new KerberosCheck();
130             if (kerberosCheck.checkKerberosAuthentication()) {
131                 System.out.println("Kerberos authentication successful");
132             } else {
133                 System.out.println("Kerberos authentication failed");
134             }
135             System.exit(0);
136         } else {
137 
138             if (GraphicsEnvironment.isHeadless()) {
139                 // force server mode
140                 LOGGER.debug("Headless mode, do not create GUI");
141                 server = true;
142             }
143             if (server) {
144                 Settings.setProperty("davmail.server", "true");
145                 Settings.updateLoggingConfig();
146             }
147 
148 
149             if (Settings.getBooleanProperty("davmail.server")) {
150                 LOGGER.debug("Start DavMail headless " + Settings.getProperty("davmail.mode") + " " + Settings.getProperty("davmail.authentication"));
151             } else {
152                 LOGGER.debug("Start DavMail with GUI " + Settings.getProperty("davmail.mode") + " " + Settings.getProperty("davmail.authentication"));
153                 DavGatewayTray.init();
154             }
155 
156             start();
157 
158             // server mode: all threads are daemon threads, do not let main stop
159             if (Settings.getBooleanProperty("davmail.server")) {
160                 Runtime.getRuntime().addShutdownHook(new Thread("Shutdown") {
161                     @Override
162                     public void run() {
163                         shutdown = true;
164                         DavGatewayTray.debug(new BundleMessage("LOG_GATEWAY_INTERRUPTED"));
165                         DavGateway.stop();
166                         synchronized (LOCK) {
167                             LOCK.notifyAll();
168                         }
169                     }
170                 });
171 
172                 synchronized (LOCK) {
173                     try {
174                         while (!shutdown) {
175                             LOCK.wait();
176                         }
177                     } catch (InterruptedException e) {
178                         DavGatewayTray.debug(new BundleMessage("LOG_GATEWAY_INTERRUPTED"));
179                         Thread.currentThread().interrupt();
180                     }
181                 }
182 
183             }
184         }
185     }
186 
187     /**
188      * Start DavMail listeners.
189      */
190     public static void start() {
191         SERVER_LIST.clear();
192 
193         int smtpPort = Settings.getIntProperty("davmail.smtpPort");
194         if (smtpPort != 0) {
195             SERVER_LIST.add(new SmtpServer(smtpPort));
196         }
197         int popPort = Settings.getIntProperty("davmail.popPort");
198         if (popPort != 0) {
199             SERVER_LIST.add(new PopServer(popPort));
200         }
201         int imapPort = Settings.getIntProperty("davmail.imapPort");
202         if (imapPort != 0) {
203             SERVER_LIST.add(new ImapServer(imapPort));
204         }
205         int caldavPort = Settings.getIntProperty("davmail.caldavPort");
206         if (caldavPort != 0) {
207             SERVER_LIST.add(new CaldavServer(caldavPort));
208         }
209         int ldapPort = Settings.getIntProperty("davmail.ldapPort");
210         if (ldapPort != 0) {
211             SERVER_LIST.add(new LdapServer(ldapPort));
212         }
213 
214         BundleMessage.BundleMessageList messages = new BundleMessage.BundleMessageList();
215         BundleMessage.BundleMessageList errorMessages = new BundleMessage.BundleMessageList();
216         for (AbstractServer server : SERVER_LIST) {
217             try {
218                 server.bind();
219                 server.start();
220                 messages.add(new BundleMessage("LOG_PROTOCOL_PORT", server.getProtocolName(), server.getPort()));
221             } catch (DavMailException e) {
222                 errorMessages.add(e.getBundleMessage());
223             }
224         }
225 
226         final String currentVersion = getCurrentVersion();
227         boolean showStartupBanner = Settings.getBooleanProperty("davmail.showStartupBanner", true);
228         if (showStartupBanner) {
229             DavGatewayTray.info(new BundleMessage("LOG_DAVMAIL_GATEWAY_LISTENING", currentVersion, messages));
230         }
231         if (!errorMessages.isEmpty()) {
232             DavGatewayTray.error(new BundleMessage("LOG_MESSAGE", errorMessages));
233             if (Settings.getBooleanProperty("davmail.exitOnBindFailed", false)) {
234                 System.exit(1);
235             }
236         }
237 
238         // check for new version in a separate thread
239         new Thread("CheckRelease") {
240             @Override
241             public void run() {
242                 String releasedVersion = getReleasedVersion();
243                 if (!currentVersion.isEmpty() && releasedVersion != null && currentVersion.compareTo(releasedVersion) < 0) {
244                     DavGatewayTray.info(new BundleMessage("LOG_NEW_VERSION_AVAILABLE", releasedVersion));
245                 }
246 
247             }
248         }.start();
249 
250     }
251 
252     /**
253      * Stop all listeners, shutdown connection pool and clear session cache.
254      */
255     public static void stop() {
256         DavGateway.stopServers();
257         // close pooled connections
258         ExchangeSessionFactory.shutdown();
259         DavGatewayTray.info(new BundleMessage("LOG_GATEWAY_STOP"));
260         DavGatewayTray.dispose();
261     }
262 
263     /**
264      * Stop all listeners and clear session cache.
265      */
266     public static void restart() {
267         DavGateway.stopServers();
268         // clear session cache
269         ExchangeSessionFactory.shutdown();
270         DavGateway.start();
271     }
272 
273     private static void stopServers() {
274         for (AbstractServer server : SERVER_LIST) {
275             server.close();
276             try {
277                 server.join();
278             } catch (InterruptedException e) {
279                 DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_WAITING_SERVER_THREAD_DIE"), e);
280                 Thread.currentThread().interrupt();
281             }
282         }
283     }
284 
285     /**
286      * Get current DavMail version.
287      *
288      * @return current version
289      */
290     public static String getCurrentVersion() {
291         Package davmailPackage = DavGateway.class.getPackage();
292         String currentVersion = davmailPackage.getImplementationVersion();
293         if (currentVersion == null) {
294             currentVersion = "";
295         }
296         return currentVersion;
297     }
298 
299     /**
300      * Get latest released version from SourceForge.
301      *
302      * @return latest version
303      */
304     public static String getReleasedVersion() {
305         String version = null;
306         if (!Settings.getBooleanProperty("davmail.disableUpdateCheck")) {
307             try (HttpClientAdapter httpClientAdapter = new HttpClientAdapter(HTTP_DAVMAIL_SOURCEFORGE_NET_VERSION_TXT)) {
308                 GetRequest getRequest = new GetRequest(HTTP_DAVMAIL_SOURCEFORGE_NET_VERSION_TXT);
309                 getRequest.setHeader("User-Agent", "curl/8.21.0");
310                 getRequest = httpClientAdapter.executeFollowRedirect(getRequest);
311                 version = getRequest.getResponseBodyAsString();
312                 LOGGER.debug("DavMail released version: " + version);
313             } catch (IOException e) {
314                 DavGatewayTray.debug(new BundleMessage("LOG_UNABLE_TO_GET_RELEASED_VERSION"));
315             }
316         }
317         return version;
318     }
319 }