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