001 /*
002 * This class is part of DocWhatsUp, a bug profiling and -reporting lib.
003 *
004 * Copyright (C)
005 *
006 * This library is free software; you can redistribute it and/or modify it
007 * under the terms of the GNU General Public License as published by the
008 * Free Software Foundation; either version 2 of the License, or (at your
009 * option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful, but
012 * WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
014 * Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License along
017 * with this program; if not, write to the Free Software Foundation, Inc.,
018 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019 *
020 * EXTENSION:
021 * Linking DocWhatsUp statically or dynamically with other modules is making a
022 * combined work based on DocWhatsUp. Thus, the terms and conditions of the
023 * GNU General Public License cover the whole combination.
024 *
025 * As a special exception, the copyright holder of DocWhatsUp give you
026 * permission to link DocWhatsUp with independent modules that communicate with
027 * DocWhatsUp solely through the DocWhatsUp.java interface, regardless of the
028 * license terms of these independent modules, and to copy and distribute the
029 * resulting combined work under terms of your choice, provided that
030 * every copy of the combined work is accompanied by a complete copy of
031 * the source code of DocWhatsUp (the version of DocWhatsUp used to produce the
032 * combined work), being distributed under the terms of the GNU General
033 * Public License plus this exception. An independent module is a module
034 * which is not derived from or based on DocWhatsUp.
035
036 * Note that people who make modified versions of DocWhatsUp are not obligated
037 * to grant this special exception for their modified versions; it is
038 * their choice whether to do so. The GNU General Public License gives
039 * permission to release a modified version without this exception; this
040 * exception also makes it possible to release a modified version which
041 * carries forward this exception.
042 *
043 * Author: Philipp Bartsch; codeshaker@gmx.net
044 */
045
046 package org.shaker.dwu;
047
048 import java.io.File;
049 import java.io.FileInputStream;
050 import java.io.FileOutputStream;
051 import java.io.IOException;
052 import java.io.InputStream;
053 import java.util.ArrayList;
054 import java.util.Properties;
055 import java.util.StringTokenizer;
056
057 import javax.mail.internet.AddressException;
058 import javax.mail.internet.InternetAddress;
059
060 /**
061 * This class manages all DocWhatsUp properties:
062 * <ul>
063 * <li>POP-Server (optional)</li>
064 * <li>POP-Server port (default 110)</li>
065 * <li>SMTP-Server</li>
066 * <li>SMTP-Server port (default 25)</li>
067 * <li>Mailaccount name (optional)</li>
068 * <li>Mailaddress.</li>
069 * </ul>
070 * The POP settings and the mailaccount name must be present for POP-Auth
071 * SMTP-Servers (like the majority of them).
072 *
073 * @author <A HREF="mailto:codeshaker@gmx.net">
074 * Philipp Bartsch (codeshaker@gmx.net)</A>,
075 * <A HREF="../../../../gpl.txt">GPL License</A>
076 */
077 final class Settings
078 extends Properties {
079
080 /**POP-Server key*/
081 static final byte POP = 1;
082 /**POP-Server port key*/
083 static final byte POP_PORT = 2;
084 /**SMTP-Server key*/
085 static final byte SMTP = 3;
086 /**SMTP-Server port key*/
087 static final byte SMTP_PORT = 4;
088 /**Mail account name key*/
089 static final byte USER = 5;
090 /**User`s mail address - key*/
091 static final byte FROM = 6;
092 /**Submission list key*/
093 static final byte SUBMITTED = 10;
094
095 /**Settings file reference*/
096 private static final File cfgFile = new File(ToolBox.DWU_PATH+
097 "settings.dwu");
098 /**Custom mail configuration file reference*/
099 private static final File cstmFile = new File(ToolBox.DWU_PATH+
100 "custom.mta");
101 /**The common settings (that also stores sigs of submitted BugProfiles)*/
102 private static final Properties cfgProps = new Properties();
103 /**The array of cc addresses, specified by settings.dwu*/
104 private final InternetAddress[] ccArray;
105 /**The array of maintainer addresses, specified by settings.dwu*/
106 private final InternetAddress[] mntArray;
107
108 /**Settings file inputstream*/
109 private FileInputStream cfgInstream;
110 /**Settings file outputstream*/
111 private FileOutputStream cfgOutstream;
112 /**Mail settings file inputstream*/
113 private InputStream propInstream;
114 /**Mail settings file outputstream*/
115 private FileOutputStream propOutstream;
116
117
118 /**
119 * Inits the Properties and loads, if present, older values.
120 */
121 Settings () {
122 ToolBox.checkUp();
123 try {
124 // load mail config
125 if (cstmFile.exists())
126 load(propInstream = new FileInputStream(cstmFile));
127 else
128 load(propInstream = ClassLoader
129 .getSystemClassLoader()
130 .getResourceAsStream("default.mta"));
131 // load configuration
132 if (cfgFile.exists()) {
133 cfgProps.load(cfgInstream = new FileInputStream(cfgFile));
134 cfgInstream.close();
135 } else
136 cfgFile.createNewFile();
137 propInstream.close();
138 } catch (IOException ioe) {
139 ToolBox.logException(ioe);
140 } finally {
141 if (getProperty("mail.host.port") == null)
142 setProperty("mail.host.port",
143 "25");
144 if (getProperty("mail.pop.port") == null)
145 setProperty("mail.pop.port",
146 "110");
147 }
148 ccArray = resolveAddrs(cfgProps.getProperty("cc"));
149 mntArray = resolveAddrs(cfgProps.getProperty("maintain"));
150 }
151
152 /**
153 * Returns true if the default or custom mail config files are present.
154 * If one of these file exists, there`s implicitly a working configuration.
155 * @see ToolBox#DWU_PATH if you want to know, where the files are located
156 *
157 * @return boolean flag
158 */
159 static final boolean isConfigurated () {
160 return cstmFile.exists()
161 || ClassLoader
162 .getSystemClassLoader()
163 .getResourceAsStream("default.mta") != null;
164 }
165
166 /**
167 * Reverts current settings and loads saved state.
168 */
169 final void revertChanges () {
170 clear();
171 if (isConfigurated()) //is there a mta to revert to?
172 try {
173 if (!cstmFile.exists())
174 propInstream = ClassLoader
175 .getSystemClassLoader()
176 .getResourceAsStream("default.mta");
177 else
178 propInstream = new FileInputStream(cstmFile);
179 load(propInstream);
180 propInstream.close();
181 } catch (IOException ioe) {
182 //hardly reachable
183 ToolBox.logException(ioe);
184 }
185 }
186
187 static final File getSettingsFile () {
188 return cfgFile;
189 }
190
191 /**
192 * Tries to delete a somehow corrupted properties file.
193 */
194 static final void killPhysically () {
195 cstmFile.delete();
196 }
197
198 /**
199 * Returns true, if the current settings could be successfully saved to
200 * disk.
201 */
202 final void applyChanges () {
203 try {
204 if (!cstmFile.exists()) {
205 cstmFile.createNewFile();
206 }
207 // don`t save users password for security reasons
208 String passwd = getProperty("mail.pass");
209 remove("mail.pass");
210 // store settings
211 store(propOutstream = new FileOutputStream(cstmFile),
212 "Donīt touch ;)");
213 propOutstream.close();
214 if (passwd != null)
215 super.setProperty("mail.pass",
216 passwd);
217 } catch (IOException ioe) {
218 ToolBox.logException(ioe);
219 }
220 }
221
222 /**
223 * Sets a mail configuration property. Used keys:
224 * <ul>
225 * <li>POP - The POP-Server</li>
226 * <li>POP_Port - The port of the POP-Server</li>
227 * <li>SMTP - THE SMTP-Server</li>
228 * <li>SMTP_PORT - The port of the SMTP-Server</li>
229 * <li>FROM - The senders mail address</li>
230 * <li>USER - The mailbox account name</li>
231 * <li>FORMAT - The standard send format of the mail body</li>
232 * </ul>
233 *
234 * @param key an int key representation of the current value
235 * @param value a string representation of the value
236 */
237 final void setProperty (final byte key,
238 final String value) {
239 switch(key) {
240 case(POP):
241 setProperty("mail.pop", value);
242 remove("mail.pass");
243 break;
244 case(POP_PORT) :
245 setProperty("mail.pop.port",
246 (value.length() == 0
247 ? "110"
248 : value));
249 remove("mail.pass");
250 break;
251 case(SMTP):
252 setProperty("mail.host", value);
253 remove("mail.pass");
254 break;
255 case(SMTP_PORT):
256 setProperty("mail.host.port",
257 (value.length() == 0
258 ? "25"
259 : value));
260 remove("mail.pass");
261 break;
262 case(FROM):
263 setProperty("mail.from", value);
264 break;
265 case(USER):
266 setProperty("mail.user", value);
267 remove("mail.pass");
268 break;
269 }
270 }
271
272 /**
273 * Returns users mail address.
274 *
275 * @return InternetAddress the mail address
276 */
277 final InternetAddress getSender () {
278 try {
279 return new InternetAddress(getProperty("mail.from"));
280 } catch (AddressException ae) {
281 return null;
282 } catch (NullPointerException npe) {
283 return null;
284 }
285 }
286
287 /**
288 * Returns true, if a password has been specified.
289 *
290 * @return true, if there`s a password
291 */
292 final boolean hasPassword () {
293 return containsKey("mail.pass");
294 }
295
296 /**
297 * Returns the specified password.
298 * see#hasPassword() that should be used to check presence
299 *
300 * @return the password
301 */
302 final String getPassword () {
303 return getProperty("mail.pass");
304 }
305
306 /**
307 * Removes the given password to force the user to reenter it.
308 * This method doesn`t delete the password of the default mail configuration!
309 */
310 final void removePassword () {
311 if (cstmFile.exists() && containsKey("mail.pass"))
312 remove("mail.pass");
313 }
314
315 /**
316 * Returns true, if a mail account has been specified.
317 *
318 * @return boolean flag
319 */
320 final boolean hasUser () {
321 return containsKey("mail.user");
322 }
323
324 /**
325 * Returns mail account name.
326 *
327 * @return String the mail account name
328 */
329 final String getUser () {
330 return getProperty("mail.user");
331 }
332
333 /**
334 * Returns true, if a pop-server has been specified.
335 *
336 * @return boolean flag
337 */
338 final boolean hasPOPServer () {
339 return containsKey("mail.pop")
340 && getProperty("mail.pop").length() > 0;
341 }
342
343 /**
344 * Return the POP-Server address.
345 *
346 * @return String the POP-Server address
347 */
348 final String getPOPServer () {
349 return getProperty("mail.pop");
350 }
351
352 /**
353 * Returns the POP-Server port.
354 *
355 * @return int the port
356 */
357 final int getPOPPort () {
358 return Integer.parseInt(getProperty("mail.pop.port"));
359 }
360
361 /**
362 * Returns true, if a mailaccount has been specified.
363 *
364 * @return boolean flag
365 */
366 final boolean hasSMTPServer () {
367 return containsKey("mail.host");
368 }
369
370 /**
371 * Returns the specified SMTP-Server address.
372 *
373 * @return String the address
374 */
375 final String getSMTPServer () {
376 return getProperty("mail.host");
377 }
378
379 /**
380 * Returns the SMTP-Server port.
381 *
382 * @return int the port
383 */
384 final int getSMTPPort () {
385 return Integer.parseInt(getProperty("mail.host.port"));
386 }
387
388 /**
389 * Returns the specified default send format or text, if nothing has been specified.
390 *
391 * @return the default format from common.properties or an empty string
392 */
393 final String getDefaultSendFormat() {
394 return (cfgProps.containsKey("format")
395 ? cfgProps.getProperty("format")
396 : "text");
397 }
398
399 /**
400 * Returns true, if "mailing" in settings.dwu has been set to "true". If you
401 * set "mailing" to "false", DWU won`t submit mails, doesn`t include the
402 * "Send Error" tab into the dialogs and ignores the submitBugQueue() method.
403 *
404 * @return true, if "mailing" in settings.dwu is set to "true"
405 */
406 final boolean isMailingEnabled () {
407 return (cfgProps.containsKey("mailing")
408 ? cfgProps.getProperty("mailing").equals("true")
409 : false);
410 }
411
412 /**
413 * Returns true, if "dialogs" in settings.dwu has been set to "true". If you
414 * set "dialogs" to "false", DWU won`t create dialogs, even if you call the
415 * appropiate methods.
416 *
417 * @return true, if "dialogs" in settings.dwu is set to "true"
418 */
419 final boolean isDialogEnabled () {
420 return (cfgProps.containsKey("dialogs")
421 ? cfgProps.getProperty("dialogs").equals("true")
422 : false);
423 }
424
425 /**
426 * Returns true, if at least one valid maintainers has been specified.
427 *
428 * @return true, if settings.dwu contains a valid "maintain" entry
429 */
430 final boolean hasMaintainer () {
431 return mntArray.length > 0;
432 }
433
434 /**
435 * Returns the address of the DWU project maintainer specified by
436 * "maintain" in settings.dwu or null, if nothing is specified. If
437 * this property is missing, DWU won`t send maintenance mails (about
438 * DWU errors).
439 *
440 * @return the addresses of the maintainer or an empty array
441 */
442 final InternetAddress[] getMaintainers () {
443 return mntArray;
444 }
445
446 /**
447 * Returns the co recipients specified by "cc" in settings.dwu.
448 *
449 * @return the cc address array
450 */
451 final InternetAddress[] getCoRecipients () {
452 return ccArray;
453 }
454
455 /**
456 * Returns true, if the settings.dwu file specified further recipients.
457 *
458 * @return cc flag
459 */
460 final boolean hasCoRecipient () {
461 return ccArray.length > 0;
462 }
463
464 /**
465 * Returns true, if a valid alternative recipient has been specified.
466 *
467 * @return true, if settings.dwu contains a valid "alt" entry
468 */
469 final boolean hasAlternativeRecipient () {
470 try {
471 if ((containsKey("alt") && cfgProps.getProperty("alt") != null))
472 new InternetAddress(cfgProps.getProperty("alt"));
473 return true;
474 } catch (AddressException ae) {
475 return false;
476 }
477 }
478
479 /**
480 * Returns the alternative recipient specified by "alt" in settings.dwu
481 * or null, if nothing is specified.
482 *
483 * @return the alternative recipient
484 */
485 final String getAlternativeRecipient () {
486 return cfgProps.getProperty("alt");
487 }
488
489 /**
490 * Returns the number of transmitted report.
491 *
492 * @return int the amount
493 */
494 final int getTransferCount () {
495
496 if (cfgProps.containsKey("submitted"))
497 return new StringTokenizer(cfgProps.getProperty("submitted"),
498 ";").countTokens();
499 else
500 return 0;
501 }
502
503 /**
504 * Registers a BugProfile as submitted.
505 *
506 * @param hashValue the hashvalue of the submitted profile
507 */
508 final void registerSubmission (final String hashValue) {
509 if (cfgProps.getProperty("submitted") == null)
510 cfgProps.setProperty("submitted",
511 hashValue + ";");
512 else
513 cfgProps.setProperty("submitted",
514 cfgProps.getProperty("submitted")
515 .concat(hashValue + ";"));
516 try {
517 cfgProps.store(cfgOutstream = new FileOutputStream(cfgFile),
518 "Please have a look at the manual first!");
519 cfgOutstream.close();
520 } catch (Exception e) {
521 ToolBox.logException(e);
522 }
523 }
524
525 /**
526 * Returns true if a BugProfile with the given hashValue has already been
527 * submitted before. This method searches for an entry of the given
528 * hashValue in section "submitted" (which keeps track of submitted hashes).
529 *
530 * @param hashValue the current StackTrace hashvalue
531 * @return boolean true if already submitted
532 */
533 final boolean alreadySubmitted (final String hashValue) {
534 return cfgProps.containsKey("submitted")
535 && cfgProps.getProperty("submitted").indexOf(hashValue) > -1;
536
537 }
538
539 /**
540 * Returns all addresses of a comma separated string containing mail
541 * addresses.
542 *
543 * @param rawList a comma separated string of addresses
544 * @return the resolved address array
545 */
546 final InternetAddress[] resolveAddrs (final String rawList) {
547 if (rawList == null || rawList.length() == 0)
548 return new InternetAddress[] {};
549
550 final ArrayList adds = new ArrayList();
551 final StringTokenizer tok = new StringTokenizer(rawList,
552 ",");
553 try {
554 while (tok.hasMoreElements()) {
555 adds.add(new InternetAddress(tok.nextElement()
556 .toString()
557 .trim()));
558 }
559 return (InternetAddress[]) adds.toArray(new InternetAddress[0]);
560 } catch (AddressException ae) {
561 if (adds.size() > 0)
562 return (InternetAddress[]) adds.toArray(new InternetAddress[0]);
563 return new InternetAddress[] {};
564 }
565 }
566 }
|