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.imap.ImapServer;
29  import davmail.ldap.LdapServer;
30  import davmail.pop.PopServer;
31  import davmail.smtp.SmtpServer;
32  import davmail.ui.tray.DavGatewayTray;
33  import org.apache.log4j.Logger;
34  
35  import java.awt.*;
36  import java.io.IOException;
37  import java.lang.reflect.InvocationTargetException;
38  import java.util.ArrayList;
39  
40  /**
41   * DavGateway main class
42   */
43  public final class DavGateway {
44      private static final Logger LOGGER = Logger.getLogger(DavGateway.class);
45      private static final String HTTP_DAVMAIL_SOURCEFORGE_NET_VERSION_TXT = "https://davmail.sourceforge.net/version.txt";
46  
47      private static final Object LOCK = new Object();
48      private static boolean shutdown = false;
49  
50      private DavGateway() {
51      }
52  
53      private static final ArrayList<AbstractServer> SERVER_LIST = new ArrayList<>();
54  
55      /**
56       * Start the gateway, listen on specified smtp and pop3 ports
57       *
58       * @param args command line parameter config file path
59       */
60      public static void main(String[] args) {
61          boolean noTray = false;
62          boolean tray = false;
63          boolean server = false;
64          boolean token = false;
65          boolean kerberos = false;
66  
67          // check environment for davmail settings path in Docker
68          String configFilePath = Settings.getConfigFilePath();
69          for (String arg : args) {
70              if (arg.startsWith("-")) {
71                  switch (arg) {
72                      case "-notray":
73                          noTray = true;
74                          break;
75                      case "-tray":
76                          tray = true;
77                          break;
78                      case "-server":
79                          server = true;
80                          break;
81                      case "-token":
82                          token = true;
83                          break;
84                      case "-kerberos":
85                          kerberos = true;
86                          break;
87                      default:
88                          LOGGER.warn("Unknown option: " + arg);
89                  }
90              } else {
91                  configFilePath = arg;
92              }
93          }
94  
95          Settings.setConfigFilePath(configFilePath);
96          Settings.load();
97  
98          // use notray / tray to override davmail.enableTray
99          if (tray) {
100             Settings.setProperty("davmail.enableTray", "true");
101         }
102         if (noTray) {
103             Settings.setProperty("davmail.enableTray", "false");
104         }
105 
106         if (token) {
107             try {
108                 ExchangeAuthenticator authenticator = (ExchangeAuthenticator) Class.forName("davmail.exchange.auth.O365InteractiveAuthenticator")
109                         .getDeclaredConstructor().newInstance();
110                 authenticator.setUsername("");
111                 authenticator.authenticate();
112                 System.out.println(authenticator.getToken().getRefreshToken());
113             } catch (IOException | ClassNotFoundException | NoSuchMethodException | InstantiationException |
114                      IllegalAccessException | InvocationTargetException e) {
115                 System.err.println(e + " " + e.getMessage());
116             }
117             // force shutdown on Linux
118             System.exit(0);
119         } else if (kerberos) {
120             KerberosCheck kerberosCheck = new KerberosCheck();
121             if (kerberosCheck.checkKerberosAuthentication()) {
122                 System.out.println("Kerberos authentication successful");
123             } else {
124                 System.out.println("Kerberos authentication failed");
125             }
126             System.exit(0);
127         } else {
128 
129             if (GraphicsEnvironment.isHeadless()) {
130                 // force server mode
131                 LOGGER.debug("Headless mode, do not create GUI");
132                 server = true;
133             }
134             if (server) {
135                 Settings.setProperty("davmail.server", "true");
136                 Settings.updateLoggingConfig();
137             }
138 
139 
140             if (Settings.getBooleanProperty("davmail.server")) {
141                 LOGGER.debug("Start DavMail in server mode");
142             } else {
143                 LOGGER.debug("Start DavMail in GUI mode");
144                 DavGatewayTray.init();
145             }
146 
147             start();
148 
149             // server mode: all threads are daemon threads, do not let main stop
150             if (Settings.getBooleanProperty("davmail.server")) {
151                 Runtime.getRuntime().addShutdownHook(new Thread("Shutdown") {
152                     @Override
153                     public void run() {
154                         shutdown = true;
155                         DavGatewayTray.debug(new BundleMessage("LOG_GATEWAY_INTERRUPTED"));
156                         DavGateway.stop();
157                         synchronized (LOCK) {
158                             LOCK.notifyAll();
159                         }
160                     }
161                 });
162 
163                 synchronized (LOCK) {
164                     try {
165                         while (!shutdown) {
166                             LOCK.wait();
167                         }
168                     } catch (InterruptedException e) {
169                         DavGatewayTray.debug(new BundleMessage("LOG_GATEWAY_INTERRUPTED"));
170                         Thread.currentThread().interrupt();
171                     }
172                 }
173 
174             }
175         }
176     }
177 
178     /**
179      * Start DavMail listeners.
180      */
181     public static void start() {
182         SERVER_LIST.clear();
183 
184         int smtpPort = Settings.getIntProperty("davmail.smtpPort");
185         if (smtpPort != 0) {
186             SERVER_LIST.add(new SmtpServer(smtpPort));
187         }
188         int popPort = Settings.getIntProperty("davmail.popPort");
189         if (popPort != 0) {
190             SERVER_LIST.add(new PopServer(popPort));
191         }
192         int imapPort = Settings.getIntProperty("davmail.imapPort");
193         if (imapPort != 0) {
194             SERVER_LIST.add(new ImapServer(imapPort));
195         }
196         int caldavPort = Settings.getIntProperty("davmail.caldavPort");
197         if (caldavPort != 0) {
198             SERVER_LIST.add(new CaldavServer(caldavPort));
199         }
200         int ldapPort = Settings.getIntProperty("davmail.ldapPort");
201         if (ldapPort != 0) {
202             SERVER_LIST.add(new LdapServer(ldapPort));
203         }
204 
205         BundleMessage.BundleMessageList messages = new BundleMessage.BundleMessageList();
206         BundleMessage.BundleMessageList errorMessages = new BundleMessage.BundleMessageList();
207         for (AbstractServer server : SERVER_LIST) {
208             try {
209                 server.bind();
210                 server.start();
211                 messages.add(new BundleMessage("LOG_PROTOCOL_PORT", server.getProtocolName(), server.getPort()));
212             } catch (DavMailException e) {
213                 errorMessages.add(e.getBundleMessage());
214             }
215         }
216 
217         final String currentVersion = getCurrentVersion();
218         boolean showStartupBanner = Settings.getBooleanProperty("davmail.showStartupBanner", true);
219         if (showStartupBanner) {
220             DavGatewayTray.info(new BundleMessage("LOG_DAVMAIL_GATEWAY_LISTENING", currentVersion, messages));
221         }
222         if (!errorMessages.isEmpty()) {
223             DavGatewayTray.error(new BundleMessage("LOG_MESSAGE", errorMessages));
224             if (Settings.getBooleanProperty("davmail.exitOnBindFailed", false)) {
225                 System.exit(1);
226             }
227         }
228 
229         // check for new version in a separate thread
230         new Thread("CheckRelease") {
231             @Override
232             public void run() {
233                 String releasedVersion = getReleasedVersion();
234                 if (!currentVersion.isEmpty() && releasedVersion != null && currentVersion.compareTo(releasedVersion) < 0) {
235                     DavGatewayTray.info(new BundleMessage("LOG_NEW_VERSION_AVAILABLE", releasedVersion));
236                 }
237 
238             }
239         }.start();
240 
241     }
242 
243     /**
244      * Stop all listeners, shutdown connection pool and clear session cache.
245      */
246     public static void stop() {
247         DavGateway.stopServers();
248         // close pooled connections
249         ExchangeSessionFactory.shutdown();
250         DavGatewayTray.info(new BundleMessage("LOG_GATEWAY_STOP"));
251         DavGatewayTray.dispose();
252     }
253 
254     /**
255      * Stop all listeners and clear session cache.
256      */
257     public static void restart() {
258         DavGateway.stopServers();
259         // clear session cache
260         ExchangeSessionFactory.shutdown();
261         DavGateway.start();
262     }
263 
264     private static void stopServers() {
265         for (AbstractServer server : SERVER_LIST) {
266             server.close();
267             try {
268                 server.join();
269             } catch (InterruptedException e) {
270                 DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_WAITING_SERVER_THREAD_DIE"), e);
271                 Thread.currentThread().interrupt();
272             }
273         }
274     }
275 
276     /**
277      * Get current DavMail version.
278      *
279      * @return current version
280      */
281     public static String getCurrentVersion() {
282         Package davmailPackage = DavGateway.class.getPackage();
283         String currentVersion = davmailPackage.getImplementationVersion();
284         if (currentVersion == null) {
285             currentVersion = "";
286         }
287         return currentVersion;
288     }
289 
290     /**
291      * Get latest released version from SourceForge.
292      *
293      * @return latest version
294      */
295     public static String getReleasedVersion() {
296         String version = null;
297         if (!Settings.getBooleanProperty("davmail.disableUpdateCheck")) {
298             try (HttpClientAdapter httpClientAdapter = new HttpClientAdapter(HTTP_DAVMAIL_SOURCEFORGE_NET_VERSION_TXT)) {
299                 GetRequest getRequest = new GetRequest(HTTP_DAVMAIL_SOURCEFORGE_NET_VERSION_TXT);
300                 getRequest.setHeader("User-Agent", "Mozilla/5.0");
301                 getRequest = httpClientAdapter.executeFollowRedirect(getRequest);
302                 version = getRequest.getResponseBodyAsString();
303                 LOGGER.debug("DavMail released version: " + version);
304             } catch (IOException e) {
305                 DavGatewayTray.debug(new BundleMessage("LOG_UNABLE_TO_GET_RELEASED_VERSION"));
306             }
307         }
308         return version;
309     }
310 }