PageRenderTime 28ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/ivatagroupware-0.11.3/webmail/src/java/com/ivata/groupware/business/mail/MailImpl.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1297 lines | 629 code | 118 blank | 550 comment | 102 complexity | b397dc966b67c582b9c6d31957d24631 MD5 | raw file
  1. /*
  2. * Copyright (c) 2001 - 2005 ivata limited.
  3. * All rights reserved.
  4. * -----------------------------------------------------------------------------
  5. * ivata groupware may be redistributed under the GNU General Public
  6. * License as published by the Free Software Foundation;
  7. * version 2 of the License.
  8. *
  9. * These programs are free software; you can redistribute them and/or
  10. * modify them under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; version 2 of the License.
  12. *
  13. * These programs are distributed in the hope that they will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. *
  17. * See the GNU General Public License in the file LICENSE.txt for more
  18. * details.
  19. *
  20. * If you would like a copy of the GNU General Public License write to
  21. *
  22. * Free Software Foundation, Inc.
  23. * 59 Temple Place - Suite 330
  24. * Boston, MA 02111-1307, USA.
  25. *
  26. *
  27. * To arrange commercial support and licensing, contact ivata at
  28. * http://www.ivata.com/contact.jsp
  29. * -----------------------------------------------------------------------------
  30. * $Log: MailImpl.java,v $
  31. * Revision 1.6.2.1 2005/10/08 17:36:37 colinmacleod
  32. * SettingDateFormatter now requires SecuritySession in constructor.
  33. *
  34. * Revision 1.6 2005/04/29 02:48:20 colinmacleod
  35. * Data bugfixes.
  36. * Changed primary key back to Integer.
  37. *
  38. * Revision 1.5 2005/04/27 15:20:09 colinmacleod
  39. * Now implements Serializable.
  40. *
  41. * Revision 1.4 2005/04/22 10:59:12 colinmacleod
  42. * Added logging when there is no mail
  43. * server and reordered this file alphabetically.
  44. *
  45. * Revision 1.3 2005/04/10 20:10:08 colinmacleod
  46. * Added new themes.
  47. * Changed id type to String.
  48. * Changed i tag to em and b tag to strong.
  49. * Improved PicoContainerFactory with NanoContainer scripts.
  50. *
  51. * Revision 1.2 2005/04/09 17:20:00 colinmacleod
  52. * Changed copyright text to GPL v2 explicitly.
  53. *
  54. * Revision 1.1.1.1 2005/03/10 17:51:15 colinmacleod
  55. * Restructured ivata op around Hibernate/PicoContainer.
  56. * Renamed ivata groupware.
  57. *
  58. * Revision 1.6 2004/11/12 15:57:23 colinmacleod
  59. * Removed dependencies on SSLEXT.
  60. * Moved Persistence classes to ivata masks.
  61. *
  62. * Revision 1.5 2004/11/03 17:15:38 colinmacleod
  63. * added addUserEmailAddresses method.
  64. * Improved setUesrAliases to check telecom addresses in the person.
  65. *
  66. * Revision 1.4 2004/09/30 15:09:33 colinmacleod
  67. * Bug fixes
  68. *
  69. * Revision 1.3 2004/07/18 21:59:24 colinmacleod
  70. * Removed Person from User - now you need to use addressbook/persistence manager to find the person (makes the app run faster.)
  71. *
  72. * Revision 1.2 2004/07/13 19:48:12 colinmacleod
  73. * Moved project to POJOs from EJBs.
  74. * Applied PicoContainer to services layer (replacing session EJBs).
  75. * Applied Hibernate to persistence layer (replacing entity EJBs).
  76. *
  77. * Revision 1.1 2004/03/27 10:31:26 colinmacleod
  78. * Split off business logic from remote facades to POJOs.
  79. *
  80. * Revision 1.6 2004/03/21 21:16:39 colinmacleod
  81. * Shortened name to ivata op.
  82. *
  83. * Revision 1.5 2004/03/21 20:51:51 colinmacleod
  84. * Change SecurityServer into interface.
  85. * Added checking of mail server.
  86. *
  87. * Revision 1.4 2004/03/10 22:43:13 colinmacleod
  88. * Added security server exception handling.
  89. *
  90. * Revision 1.3 2004/02/10 19:57:26 colinmacleod
  91. * Changed email address.
  92. *
  93. * Revision 1.2 2004/02/01 22:07:32 colinmacleod
  94. * Added full names to author tags
  95. *
  96. * Revision 1.1.1.1 2004/01/27 20:59:56 colinmacleod
  97. * Moved ivata openportal to SourceForge..
  98. *
  99. * Revision 1.6 2003/12/12 13:24:34 jano
  100. * fixing webmail functionality
  101. *
  102. * Revision 1.5 2003/11/03 11:31:06 jano
  103. * commiting webmail,
  104. * tryinjg to fix deploying problem
  105. *
  106. * Revision 1.4 2003/10/28 13:27:51 jano
  107. * commiting webmail,
  108. * still fixing compile and building openGroupware project
  109. *
  110. * Revision 1.3 2003/10/15 14:13:00 jano
  111. * converting to XDoclet
  112. *
  113. * Revision 1.2 2003/10/15 14:11:33 colin
  114. * fixing for XDoclet
  115. *
  116. * Revision 1.25 2003/07/15 06:43:40 peter
  117. * fixed the last fix
  118. *
  119. * Revision 1.24 2003/07/15 06:01:59 peter
  120. * fixed message text bugs and composed attachments size bug
  121. *
  122. * Revision 1.23 2003/07/14 15:04:22 jano
  123. * peter: fixed invisible attachments problem
  124. *
  125. * Revision 1.22 2003/07/14 14:52:24 jano
  126. * fixing bug in mailBean
  127. *
  128. * Revision 1.21 2003/07/11 06:31:06 peter
  129. * fixed text logic in alternative multiparts
  130. *
  131. * Revision 1.20 2003/07/07 13:43:32 peter
  132. * fixed getAttachment for cases with fileName
  133. *
  134. * Revision 1.19 2003/06/22 21:28:10 peter
  135. * re-fixed attachment handling for multipart cases
  136. *
  137. * Revision 1.18 2003/06/20 18:31:03 peter
  138. * added incorrectly composed mail forwards and self contained attachment like email handling
  139. *
  140. * Revision 1.17 2003/06/19 10:06:08 jano
  141. * add check boxies in registration proces of customer
  142. *
  143. * Revision 1.16 2003/06/02 06:30:19 peter
  144. * create reply and forward message fixed
  145. *
  146. * Revision 1.15 2003/05/28 05:41:21 peter
  147. * added fileName as secondary attachments identifier, when contentId not present
  148. *
  149. * Revision 1.14 2003/05/27 17:15:12 peter
  150. * getAttachment fixed, private getAttachment methnod added
  151. *
  152. * Revision 1.13 2003/05/15 08:21:12 peter
  153. * fixed addMultipart logic - some multipart types weren't included
  154. *
  155. * Revision 1.12 2003/05/14 11:22:07 peter
  156. * fixed bug: getDOFromJavamailMessage was called after folder closed in appendAttachmnets
  157. *
  158. * Revision 1.11 2003/05/13 15:24:18 peter
  159. * attachment compose changes
  160. *
  161. * Revision 1.10 2003/05/12 16:31:13 peter
  162. * attachment compose changes
  163. *
  164. * Revision 1.9 2003/04/01 17:58:52 colin
  165. * removed boolean from InternetAddress constructor (marked as private in my JVM)
  166. *
  167. * Revision 1.8 2003/03/25 16:18:30 peter
  168. * fixed email address validation
  169. *
  170. * Revision 1.7 2003/03/25 08:23:29 jano
  171. * if there is no message in folder -> return null
  172. * and validate the email addresses
  173. *
  174. * Revision 1.6 2003/03/14 10:26:46 jano
  175. * adding backdoor man functionality
  176. * backdoor man = briezky
  177. *
  178. * Revision 1.5 2003/03/03 16:57:12 colin
  179. * converted localization to automatic paths
  180. * added labels
  181. * added mandatory fieldName attribute
  182. *
  183. * Revision 1.4 2003/02/28 10:23:27 peter
  184. * fixed handling of plain - one part messages in getDOFromJavaMailMessage
  185. *
  186. * Revision 1.3 2003/02/27 17:23:09 peter
  187. * Changed the return type of getAttachment to FileContentDO
  188. *
  189. * Revision 1.2 2003/02/25 11:53:33 colin
  190. * bugfixes and minor restructuring
  191. *
  192. * Revision 1.1 2003/02/24 19:09:24 colin
  193. * moved to business
  194. *
  195. * Revision 1.38 2003/02/20 20:26:15 colin
  196. * improved validation by adding ValidationField and ValidationException
  197. *
  198. * Revision 1.37 2003/02/04 17:39:21 colin
  199. * copyright notice
  200. *
  201. * Revision 1.36 2003/01/15 15:43:56 colin
  202. * re-implemented:
  203. * forwarding/replying (also to multiple messages)
  204. * moving messages
  205. *
  206. * Revision 1.35 2002/11/20 09:21:23 peter
  207. * removed duplicated function contents getDOFrom... (Jbuilder bug)
  208. *
  209. * Revision 1.34 2002/11/17 20:01:24 colin
  210. * speed improvements in findMessagesInFolder...
  211. *
  212. * Revision 1.33 2002/11/12 09:12:38 colin
  213. * structural changes. currently mail bean composes and reads messages but
  214. * attachment & thread handling not active
  215. *
  216. * Revision 1.32 2002/10/25 08:31:44 peter
  217. * mailFolderSent setting name changed to emailFolderSent
  218. *
  219. * Revision 1.31 2002/10/23 12:44:37 jano
  220. * using new method for get System userName
  221. *
  222. * Revision 1.30 2002/10/23 09:18:59 jano
  223. * there is a new method for generating SystemUserName
  224. *
  225. * Revision 1.29 2002/10/18 09:18:48 colin
  226. * check users to make sure they are enabled before sending them mail
  227. *
  228. * Revision 1.28 2002/10/14 11:15:46 peter
  229. * fixed a bug in (precomposed) send method, the cc fields work now
  230. *
  231. * Revision 1.27 2002/10/11 10:05:38 jano
  232. * add PREFIX to user name for difren site
  233. *
  234. * Revision 1.26 2002/10/10 14:03:57 peter
  235. * changes due to demo version
  236. *
  237. * Revision 1.25 2002/10/01 05:59:47 peter
  238. * modifications in (precomposed) send method
  239. *
  240. * Revision 1.24 2002/09/17 07:26:24 peter
  241. * working version
  242. *
  243. * Revision 1.23 2002/09/16 16:26:40 peter
  244. * the attachments stuff works....
  245. *
  246. * Revision 1.22 2002/09/13 13:59:17 peter
  247. * appendMessages and setDO methods tuned...
  248. * it still doesn't work properly
  249. *
  250. * Revision 1.21 2002/09/12 15:55:25 peter
  251. * tuned createMessage and setDO
  252. *
  253. * Revision 1.20 2002/09/12 07:26:19 colin
  254. * added vacation message and user alias methods
  255. *
  256. * Revision 1.19 2002/09/11 15:57:48 peter
  257. * finished createMessage and setDO, debugging needed yet
  258. *
  259. * Revision 1.18 2002/09/11 11:33:12 peter
  260. * moveMessage works, works on createMessage and setDO
  261. *
  262. * Revision 1.17 2002/09/10 15:38:51 peter
  263. * MailBean: works on methods
  264. *
  265. * Revision 1.16 2002/09/10 14:18:51 peter
  266. * MailBean: works on methods
  267. *
  268. * Revision 1.15 2002/09/10 08:20:16 peter
  269. * MailBean: added moveMessage method
  270. *
  271. * Revision 1.14 2002/09/09 16:07:37 peter
  272. * added and modified methods in mail/MailBean
  273. *
  274. * Revision 1.13 2002/09/09 08:27:24 colin
  275. * changed mail bean from stateful to stateless
  276. * added new MailSession class
  277. *
  278. * Revision 1.12 2002/08/30 09:50:31 colin
  279. * changed canUser... methods to just can...
  280. *
  281. * Revision 1.11 2002/08/29 12:23:06 peter
  282. * mail display works...
  283. *
  284. * Revision 1.10 2002/08/27 15:26:25 peter
  285. * worked on getDO, should be finished
  286. *
  287. * Revision 1.9 2002/08/26 15:30:14 peter
  288. * MessageDO integration, not finished yet
  289. *
  290. * Revision 1.8 2002/08/26 11:15:47 peter
  291. * added getDo and the basic methods work
  292. *
  293. * Revision 1.7 2002/08/23 08:09:37 peter
  294. * design for MailBean methods, display so far
  295. *
  296. * Revision 1.6 2002/08/16 12:35:22 peter
  297. * fiixed a minor bug in getMessage method
  298. *
  299. * Revision 1.5 2002/08/16 11:59:00 peter
  300. * new mail accessing methods
  301. *
  302. * Revision 1.4 2002/08/11 11:37:50 colin
  303. * added routines to handle server activation and passivisation
  304. *
  305. * Revision 1.3 2002/07/26 13:08:06 colin
  306. * first version with mail server support
  307. *
  308. * Revision 1.2 2002/07/15 13:29:27 jano
  309. * added CreateException
  310. *
  311. * Revision 1.1 2002/07/15 07:51:04 colin
  312. * added new Mail EJB and local interface to settings
  313. * -----------------------------------------------------------------------------
  314. */
  315. package com.ivata.groupware.business.mail;
  316. import java.io.ByteArrayOutputStream;
  317. import java.io.File;
  318. import java.io.IOException;
  319. import java.io.InputStream;
  320. import java.io.Serializable;
  321. import java.text.MessageFormat;
  322. import java.util.Arrays;
  323. import java.util.Calendar;
  324. import java.util.Collection;
  325. import java.util.Date;
  326. import java.util.GregorianCalendar;
  327. import java.util.Iterator;
  328. import java.util.List;
  329. import java.util.Set;
  330. import java.util.TreeMap;
  331. import java.util.Vector;
  332. import javax.activation.DataHandler;
  333. import javax.activation.DataSource;
  334. import javax.activation.FileDataSource;
  335. import javax.mail.Address;
  336. import javax.mail.AuthenticationFailedException;
  337. import javax.mail.Flags;
  338. import javax.mail.Folder;
  339. import javax.mail.FolderNotFoundException;
  340. import javax.mail.Message;
  341. import javax.mail.MessagingException;
  342. import javax.mail.NoSuchProviderException;
  343. import javax.mail.Part;
  344. import javax.mail.Session;
  345. import javax.mail.Store;
  346. import javax.mail.Transport;
  347. import javax.mail.internet.AddressException;
  348. import javax.mail.internet.InternetAddress;
  349. import javax.mail.internet.MimeBodyPart;
  350. import javax.mail.internet.MimeMessage;
  351. import javax.mail.internet.MimeMultipart;
  352. import javax.mail.internet.MimePart;
  353. import org.apache.log4j.Logger;
  354. import com.ivata.groupware.admin.security.server.SecurityServer;
  355. import com.ivata.groupware.admin.security.server.SecurityServerException;
  356. import com.ivata.groupware.admin.security.server.SecuritySession;
  357. import com.ivata.groupware.admin.security.user.UserDO;
  358. import com.ivata.groupware.admin.setting.Settings;
  359. import com.ivata.groupware.admin.setting.SettingsDataTypeException;
  360. import com.ivata.groupware.business.addressbook.AddressBook;
  361. import com.ivata.groupware.business.addressbook.person.PersonDO;
  362. import com.ivata.groupware.business.addressbook.telecomaddress.TelecomAddressConstants;
  363. import com.ivata.groupware.business.addressbook.telecomaddress.TelecomAddressDO;
  364. import com.ivata.groupware.business.drive.file.FileContentDO;
  365. import com.ivata.groupware.business.drive.file.FileDO;
  366. import com.ivata.groupware.business.mail.message.MessageDO;
  367. import com.ivata.groupware.business.mail.message.MessageNotFoundException;
  368. import com.ivata.groupware.business.mail.server.MailServer;
  369. import com.ivata.groupware.business.mail.server.NoMailServerException;
  370. import com.ivata.groupware.business.mail.session.MailSession;
  371. import com.ivata.groupware.util.SettingDateFormatter;
  372. import com.ivata.groupware.web.format.EmailAddressFormatter;
  373. import com.ivata.groupware.web.format.SanitizerFormat;
  374. import com.ivata.mask.Mask;
  375. import com.ivata.mask.MaskFactory;
  376. import com.ivata.mask.util.SerializedByteArray;
  377. import com.ivata.mask.util.StringHandling;
  378. import com.ivata.mask.util.SystemException;
  379. import com.ivata.mask.validation.ValidationError;
  380. import com.ivata.mask.validation.ValidationErrors;
  381. import com.ivata.mask.web.format.CharacterEntityFormat;
  382. import com.ivata.mask.web.format.FormatConstants;
  383. import com.ivata.mask.web.format.HTMLFormatter;
  384. import com.ivata.mask.web.format.LineBreakFormat;
  385. import com.ivata.mask.web.tag.webgui.list.ListColumnComparator;
  386. /**
  387. * <p>This session bean provides an interface to the mail system. Every mail
  388. * operation for retrieving deleting and sending messages takes place in this
  389. * class.</p>
  390. *
  391. * @since 2002-07-12
  392. * @author Colin MacLeod
  393. * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
  394. * @author Peter Illes
  395. * @version $Revision: 1.6.2.1 $
  396. */
  397. public class MailImpl implements Mail, Serializable {
  398. /**
  399. * <p>Used to return both the HTML & plain text parts of a message in
  400. * <code>createThreadMessage</code>.</p>
  401. */
  402. private class MessageTextParts {
  403. public MimeBodyPart HTMLPart = null;
  404. public MimeBodyPart textPart = null;
  405. }
  406. /**
  407. * Logger for this class.
  408. */
  409. private static Logger logger = Logger.getLogger(MailImpl.class);
  410. private AddressBook addressBook;
  411. private SettingDateFormatter dateFormatter = null;
  412. private MailServer mailServer;
  413. MaskFactory maskFactory;
  414. /**
  415. * <p>
  416. * Settings implementation. Used to retrieve the email address host.
  417. * </p>
  418. */
  419. private Settings settings;
  420. /**
  421. * <p>
  422. * Initialize the mail implementation.
  423. * </p>
  424. *
  425. * @param securityServer A valid security server for the current site. If
  426. * this is not an instance of {@link com.ivata.groupware.business.mail.server.MailServer}
  427. * the mail implementation will not be usable.
  428. * @param persistenceManager This is used to save/access data from the
  429. * persistence store.
  430. * @param addressBook This is used to read contacts email details.
  431. * @param settings Contains user defined settings and preferences.
  432. * @param dateFormatter Used to format mail dates and times.
  433. * @param idDispenser
  434. */
  435. public MailImpl(SecurityServer securityServer,
  436. AddressBook addressBook,
  437. Settings settings,
  438. MaskFactory maskFactory) {
  439. assert (securityServer != null);
  440. if (securityServer instanceof MailServer) {
  441. this.mailServer = (MailServer) securityServer;
  442. } else {
  443. logger.warn("Security server class ("
  444. + securityServer.getClass().getName()
  445. + ") is not a mail server class.");
  446. }
  447. this.settings = settings;
  448. this.addressBook = addressBook;
  449. this.maskFactory = maskFactory;
  450. }
  451. private void checkDateFormatter(SecuritySession securitySession) {
  452. if (dateFormatter == null) {
  453. dateFormatter = new SettingDateFormatter(securitySession,
  454. settings);
  455. }
  456. }
  457. /**
  458. * <p>Add a composed message to the drafts folder for later sending.</p>
  459. *
  460. * @param mailSession valid mail session to which the user should already be
  461. * logged in.
  462. * @param messageDO data object containing full details of the
  463. * message to be added to the drafts.
  464. * @return new <code>MessageDO</code> with the <code>id</code> set to the
  465. * current value in the mail system.
  466. */
  467. public MessageDO addMessageToDraftsFolder(final MailSession mailSession,
  468. final MessageDO messageDO) throws SystemException {
  469. checkDateFormatter(mailSession);
  470. Store store = mailServer.connectStore(mailSession);
  471. try {
  472. Session javaMailSession;
  473. try {
  474. javaMailSession = mailSession.getJavaMailSession();
  475. } catch (java.security.NoSuchProviderException e1) {
  476. throw new SystemException(e1);
  477. }
  478. // get the drafts folder in case we want to copy over an older mail
  479. Folder draftsFolder = openDraftsFolder(store, mailSession);
  480. MimeMessage newMessage = setDOToJavaMailMessage(javaMailSession,
  481. draftsFolder, messageDO);
  482. newMessage.setSentDate(Calendar.getInstance().getTime());
  483. // append the new message to the drafts folder
  484. Message[] messages = { newMessage };
  485. draftsFolder.appendMessages(messages);
  486. // note the new id
  487. messageDO.setMessageID(((MimeMessage) draftsFolder.getMessage(
  488. draftsFolder.getMessageCount())).getMessageID());
  489. // only now can we delete/expunge the old mail from the drafts folder
  490. draftsFolder.expunge();
  491. draftsFolder.close(true);
  492. } catch (MessagingException e1) {
  493. throw new SystemException(e1);
  494. } finally {
  495. try {
  496. store.close();
  497. } catch (MessagingException e) {
  498. logger.error("Messaging exception on closing the store", e);
  499. }
  500. }
  501. return messageDO;
  502. }
  503. /**
  504. * <p>Recursive routine used for building up all attachments in the
  505. * <code>MessageDO<code> provided.</p>
  506. *
  507. * @param messagePart the multipart part or message to process.
  508. * @param messageDO the data object to add results to.
  509. * @throws GroupwareException if there is a <code>MailMessagingException</code> or
  510. * <code>IOException</code>.
  511. */
  512. private void addMultiPart(final Part messagePart,
  513. final MessageDO messageDO)
  514. throws SystemException {
  515. String outputText = "";
  516. MimeMultipart content;
  517. MimeBodyPart subPart;
  518. List messageTextParts = new Vector();
  519. try {
  520. content = (MimeMultipart) messagePart.getContent();
  521. //go through all the subParts
  522. for (int i = 0; i < content.getCount(); i++) {
  523. subPart = (MimeBodyPart) content.getBodyPart(i);
  524. // when multipart/alternative and no text found in parent call,
  525. // store the text of the parts to select the best one after the loop
  526. if (messagePart.isMimeType("multipart/alternative") &&
  527. subPart.isMimeType("text/*") &&
  528. StringHandling.isNullOrEmpty(messageDO.getText())) {
  529. messageTextParts.add(subPart);
  530. } else if (messagePart.isMimeType("multipart/*")) {
  531. // other multipart types
  532. if (StringHandling.isNullOrEmpty(messageDO.getText()) &&
  533. (subPart.getDisposition() == null) &&
  534. (subPart.getFileName() == null)) {
  535. if (subPart.isMimeType("text/*")) {
  536. messageTextParts.add(subPart);
  537. } else if (subPart.isMimeType("multipart/*")) {
  538. addMultiPart((Part) subPart, messageDO);
  539. } else {
  540. addPart(subPart, messageDO);
  541. }
  542. } else {
  543. if (subPart.isMimeType("multipart/*")) {
  544. addMultiPart((Part) subPart, messageDO);
  545. } else {
  546. addPart(subPart, messageDO);
  547. }
  548. }
  549. }
  550. }
  551. // looking for best message text
  552. if (!messageTextParts.isEmpty()) {
  553. String HTML = null;
  554. String text = null;
  555. // let's choose the best text
  556. for (Iterator i = messageTextParts.iterator(); i.hasNext();) {
  557. subPart = (MimeBodyPart) i.next();
  558. if (subPart.isMimeType("text/HTML")) {
  559. HTML = (String) subPart.getContent();
  560. } else if (subPart.isMimeType("text/plain")) {
  561. text = (String) subPart.getContent();
  562. }
  563. // TODO: we could use text/enriched too
  564. }
  565. if (HTML != null) {
  566. messageDO.setText(HTML);
  567. messageDO.setFormat(FormatConstants.FORMAT_HTML);
  568. } else if (text != null) {
  569. messageDO.setText(text);
  570. messageDO.setFormat(FormatConstants.FORMAT_TEXT);
  571. }
  572. }
  573. } catch (MessagingException e) {
  574. throw new SystemException(e);
  575. } catch (java.io.IOException e) {
  576. throw new SystemException(e);
  577. }
  578. }
  579. /**
  580. * <p>Add a part of a multi-part message to the attachments of the message
  581. * data object.</p>
  582. *
  583. * @param part the message part to process.
  584. * @param messageDO the data object to add results to.
  585. * @throws GroupwareException if there is a <code>MessagingException</code> or an
  586. * <code>IOException</code>.
  587. */
  588. private void addPart(final MimePart part,
  589. final MessageDO messageDO)
  590. throws SystemException {
  591. FileDO attachment = new FileDO();
  592. try {
  593. attachment.setMimeType(part.getContentType());
  594. attachment.setSize(new Integer(part.getSize()));
  595. String contentId = part.getContentID();
  596. String name = part.getFileName();
  597. // return with empty hands if no identifier, the attachment will be
  598. // impossible to locate
  599. if ((contentId == null) && (name == null)) {
  600. return;
  601. }
  602. // prefer contentId as identifier and name as the display info
  603. attachment.setName((contentId != null) ? contentId : name);
  604. attachment.setComment((name != null) ? name : contentId);
  605. } catch (MessagingException e) {
  606. throw new SystemException(e);
  607. }
  608. messageDO.getAttachments().add(attachment);
  609. }
  610. /**
  611. * <p>Internal helper to add a message to the sent mail folder. This should
  612. * be called <em><u>after</u></em> sending the mail.</p>
  613. */
  614. private void addToSentFolder(final MailSession mailSession,
  615. final MimeMessage message)
  616. throws SystemException {
  617. Folder sentFolder;
  618. Store store = mailServer.connectStore(mailSession);
  619. try {
  620. String sentFolderName = settings.getStringSetting(
  621. mailSession,
  622. "emailFolderSent",
  623. mailSession.getUser());
  624. sentFolder = mailServer.getFolder(mailSession, store, sentFolderName);
  625. if (!sentFolder.exists()) {
  626. try {
  627. if (!sentFolder.create(Folder.HOLDS_MESSAGES)) {
  628. throw new SystemException(
  629. "There was no sent folder for you on this server, "
  630. + "and ivata mail could not create one.<br>Please "
  631. + "contact your administrator.");
  632. }
  633. } catch (MessagingException e1) {
  634. throw new SystemException(e1);
  635. }
  636. }
  637. Message[] messages = { message };
  638. try {
  639. sentFolder.appendMessages(messages);
  640. } catch (MessagingException eAppend) {
  641. throw new SystemException(
  642. "There was an error adding your message to the sent "
  643. + "messages folder: " +
  644. eAppend.getMessage(),
  645. eAppend);
  646. }
  647. } catch (MessagingException eNoSent) {
  648. throw new SystemException("Sent folder not available in store. " +
  649. eNoSent.getMessage(),
  650. eNoSent);
  651. } catch (SettingsDataTypeException e) {
  652. throw new SystemException(e);
  653. } finally {
  654. try {
  655. store.close();
  656. } catch (MessagingException e) {
  657. logger.error("Messaging exception on closing the store", e);
  658. }
  659. }
  660. }
  661. /**
  662. * <p>
  663. * Add appropriate user addresses given a list of user aliases.
  664. * </p>
  665. *
  666. * @param securitySession valid security session.
  667. * @param userName name of the user who owns teh aliases.
  668. * @param userAliases a <code>Collection</code> of <code>String</code>
  669. * instances containing the local part of the different email aliases
  670. * this user has. If the user has no aliaes, an empty collection should
  671. * be provided.
  672. * @param telecomAddresess a <code>Collection</code> containing all the
  673. * user's existing email addresses, as <code>TelecomAddressDO</code>
  674. * instances.
  675. */
  676. public void addUserAliasEmailAddresses(final SecuritySession securitySession,
  677. final String userName,
  678. final Collection userAliases,
  679. final Collection telecomAddresses,
  680. final String emailAddressHost)
  681. throws SystemException {
  682. checkDateFormatter(securitySession);
  683. Iterator telecomAddressIterator = telecomAddresses.iterator();
  684. List currentAddresses = new Vector();
  685. while (telecomAddressIterator.hasNext()) {
  686. TelecomAddressDO thisTelecomAddress = (TelecomAddressDO)
  687. telecomAddressIterator.next();
  688. if (!StringHandling.isNullOrEmpty(thisTelecomAddress.getAddress())
  689. && (thisTelecomAddress.getType() == TelecomAddressConstants.TYPE_EMAIL)) {
  690. currentAddresses.add(thisTelecomAddress.getAddress());
  691. }
  692. }
  693. // if the person has no email address, give him/her one
  694. // check there is at least one alias - the following routine will
  695. // do the rest
  696. // we make it conditional because you might not always want to have
  697. // user@host as your email address - this way, you can specify a
  698. // different one
  699. if ((currentAddresses.size() == 0)
  700. && (userAliases.size() == 0)) {
  701. userAliases.add(userName);
  702. }
  703. // go thro' all aliases and create email addreses from them
  704. Iterator aliasIterator = userAliases.iterator();
  705. while(aliasIterator.hasNext()) {
  706. String alias = (String) aliasIterator.next();
  707. String aliasAddress = alias + "@" + emailAddressHost;
  708. // if it is already there, move on...
  709. if (currentAddresses.contains(aliasAddress)) {
  710. continue;
  711. }
  712. TelecomAddressDO newAddress = new TelecomAddressDO();
  713. newAddress.setAddress(aliasAddress);
  714. newAddress.setType(TelecomAddressConstants.TYPE_EMAIL);
  715. newAddress.setNumber(telecomAddresses.size());
  716. telecomAddresses.add(newAddress);
  717. }
  718. }
  719. /**
  720. * <p>Append attachments to a message located in the drafts folder.</p>
  721. *
  722. * @param mailSession valid mail session to which the user should already be
  723. * logged in.
  724. * @param id the unique identifier of the message to which we want to append
  725. * attachments.
  726. * @param attachments <code>List</code> of <code>String</code>s -
  727. * filenames of files waiting in upload directory.
  728. * @return <code>null</code> when the operation failed, otherwise the new
  729. * message id.
  730. * @exception MessageNotFoundException if the folder doesn't exist, or there
  731. * is no matching mail in this folder.
  732. *
  733. * @ejb.interface-method
  734. * view-type = "remote"
  735. */
  736. public MessageDO appendAttachments(final MailSession mailSession,
  737. final String id,
  738. final List attachments) throws SystemException {
  739. checkDateFormatter(mailSession);
  740. String newId = null;
  741. UserDO user = mailSession.getUser();
  742. Store store = mailServer.connectStore(mailSession);
  743. try {
  744. String siteHome = settings.getStringSetting(mailSession,
  745. "siteHome", user);
  746. String uploadDirectory = siteHome + "/users/" +
  747. mailSession.authenticator.getPasswordAuthentication()
  748. .getUserName() + "/upload/files/";
  749. Session javaMailSession;
  750. try {
  751. javaMailSession = mailSession.getJavaMailSession();
  752. } catch (SecurityServerException e) {
  753. throw new SystemException(e);
  754. } catch (java.security.NoSuchProviderException e) {
  755. throw new SystemException(e);
  756. }
  757. Folder draftsFolder = openDraftsFolder(store, mailSession);
  758. MimeMessage oldMessage = findJavaMailMessageByFolderMessageId(draftsFolder,
  759. id);
  760. int i;
  761. MimeBodyPart newPart;
  762. MimeMultipart newMessageContent = new MimeMultipart();
  763. MimeMultipart oldMessageContent;
  764. MimeMessage newMessage = copyJavaMailMessage(javaMailSession,
  765. oldMessage);
  766. // when the message is already multipart/mixed, no probs...
  767. if (oldMessage.isMimeType("multipart/mixed")) {
  768. oldMessageContent = (MimeMultipart) oldMessage.getContent();
  769. for (i = 0; i < oldMessageContent.getCount(); i++) {
  770. newPart = (MimeBodyPart) oldMessageContent.getBodyPart(i);
  771. newMessageContent.addBodyPart(newPart);
  772. }
  773. } else {
  774. // create the first part from the old message, attachments will be appended
  775. newPart = new MimeBodyPart();
  776. newPart.setContent(oldMessage.getContent(),
  777. oldMessage.getContentType());
  778. newPart.setHeader("Content-Type", oldMessage.getContentType());
  779. newMessageContent.addBodyPart(newPart);
  780. }
  781. // add the attachments, passed as fileNames of files in upload dir
  782. for (Iterator attachmentsIterator = attachments.iterator();
  783. attachmentsIterator.hasNext();) {
  784. File attachment = new File(uploadDirectory,
  785. (String) attachmentsIterator.next());
  786. // process the file in upload directory
  787. if (attachment.canRead()) {
  788. newPart = new MimeBodyPart();
  789. newPart.setFileName(attachment.getName());
  790. newPart.setDisposition(Part.ATTACHMENT);
  791. DataSource dataSource = new FileDataSource(attachment);
  792. newPart.setDataHandler(new DataHandler(dataSource));
  793. newPart.setHeader("Content-Type",
  794. dataSource.getContentType());
  795. newPart.setHeader("Content-Transfer-Encoding", "base64");
  796. newMessageContent.addBodyPart(newPart);
  797. }
  798. }
  799. newMessage.setContent(newMessageContent);
  800. newMessage.setHeader("Content-Type",
  801. newMessageContent.getContentType());
  802. // first append the new message
  803. Message[] messages = { newMessage };
  804. draftsFolder.appendMessages(messages);
  805. // note the new id
  806. newId = ((MimeMessage) draftsFolder.getMessage(draftsFolder.getMessageCount())).getMessageID();
  807. // only now is it safe to delete the old message
  808. oldMessage.setFlag(Flags.Flag.DELETED, true);
  809. draftsFolder.expunge();
  810. // now it's safe to delete the files in upload dir, they're in the new multipart
  811. for (Iterator attachmentsIterator = attachments.iterator();
  812. attachmentsIterator.hasNext();) {
  813. File attachment = new File(uploadDirectory,
  814. (String) attachmentsIterator.next());
  815. if (attachment.canWrite()) {
  816. attachment.delete();
  817. }
  818. }
  819. // MessageDO returnDO = getDOFromJavaMailMessage(newMessage, true);
  820. MessageDO returnDO = getDOFromJavaMailMessage(
  821. findJavaMailMessageByFolderMessageId(
  822. draftsFolder, newId), true);
  823. draftsFolder.close(true);
  824. return returnDO;
  825. } catch (MessagingException em) {
  826. throw new SystemException(em);
  827. } catch (IOException eio) {
  828. throw new SystemException(eio);
  829. } finally {
  830. try {
  831. store.close();
  832. } catch (MessagingException e) {
  833. logger.error("Messaging exception on closing the store", e);
  834. }
  835. }
  836. }
  837. /**
  838. * <p>
  839. * Check we have a valid mail server.
  840. * </p>
  841. *
  842. * @throws NoMailServerException if there is no mail server.
  843. */
  844. private void checkMailServer() throws SystemException {
  845. if (mailServer == null) {
  846. logger.warn("No mail server found.");
  847. throw new NoMailServerException();
  848. }
  849. }
  850. /**
  851. * <p>Helper method. Converts recipients from a collection of
  852. * <code>PersonDO</code>, <code>UserDO</code> or <code>String<code>
  853. * instances into an array of email addresses.</p>
  854. * @param securitySession TODO
  855. * @param addresses a <code>Collection</code> containing all of the email
  856. * addresses to convert. These can either be as <code>String<code>
  857. * instances or <code>PersonDO<code> instances, where the default
  858. * email address for each person is taken.
  859. *
  860. * @return array or <code>InternetAddress</code> instances for each of the
  861. * input parameters.
  862. */
  863. private InternetAddress[] convertAddresses(final SecuritySession securitySession,
  864. final Collection addresses)
  865. throws SystemException {
  866. InternetAddress[] returnAddresses = new InternetAddress[addresses.size()];
  867. // prerequisites check we got given something to convert
  868. if (addresses == null) {
  869. return returnAddresses;
  870. }
  871. int index = 0;
  872. for (Iterator i = addresses.iterator(); i.hasNext();) {
  873. Object item = i.next();
  874. String addressString = null;
  875. if (PersonDO.class.isInstance(item)) {
  876. PersonDO person = (PersonDO) item;
  877. addressString = person.getEmailAddress();
  878. } else if (UserDO.class.isInstance(item)) {
  879. UserDO user = (UserDO) item;
  880. PersonDO person = addressBook.findPersonByUserName(securitySession,
  881. user.getName());
  882. // only set the address for users who are not disabled
  883. if (user.isEnabled()) {
  884. addressString = person.getEmailAddress();
  885. }
  886. } else {
  887. if (!String.class.isInstance(item)) {
  888. throw new SystemException("Cannot convert item of class '" +
  889. item.getClass() + "' into an email address.");
  890. }
  891. addressString = (String) item;
  892. }
  893. // ignore empty addresses
  894. if (!StringHandling.isNullOrEmpty(addressString)) {
  895. try {
  896. returnAddresses[index++] = new InternetAddress(addressString);
  897. } catch (AddressException eAddress) {
  898. throw new SystemException(
  899. "ERROR in MailBean: cannot convert internet address '"
  900. + addressString
  901. + "': "
  902. + eAddress.getMessage(),
  903. eAddress);
  904. }
  905. }
  906. }
  907. return returnAddresses;
  908. }
  909. /**
  910. * <p>Copy the fields of an old <code>MimeMessage</code> to a new one.</p>
  911. *
  912. * <p><strong>Note:</strong> this method does not copy the content. Both the text
  913. * and the message attachments (if any) must be set individually.</p>
  914. *
  915. * @param javaMailSession valid <em>JavaMail</em> session to which the user
  916. * should already be logged in.
  917. * @param message a valid message filled out with values to copy.
  918. * @return a valid <em>JavaMail</em> message ready with <code>recipients</code>,
  919. * <code>from</code> and <code>subject</code> fields matching
  920. * <code>message</code>.
  921. */
  922. private MimeMessage copyJavaMailMessage(final Session javaMailSession,
  923. final MimeMessage message)
  924. throws SystemException {
  925. MimeMessage newMessage = new MimeMessage(javaMailSession);
  926. try {
  927. newMessage.setRecipients(Message.RecipientType.TO,
  928. message.getRecipients(Message.RecipientType.TO));
  929. newMessage.setRecipients(Message.RecipientType.CC,
  930. message.getRecipients(Message.RecipientType.CC));
  931. newMessage.setRecipients(Message.RecipientType.BCC,
  932. message.getRecipients(Message.RecipientType.BCC));
  933. newMessage.addFrom(message.getFrom());
  934. newMessage.setSubject(message.getSubject());
  935. } catch (MessagingException e) {
  936. throw new SystemException(e);
  937. }
  938. return newMessage;
  939. }
  940. /**
  941. * <p>Convert a <em>JavaMail</em> message to an <em>ivata groupware</em> dependent
  942. * value object.</p>
  943. *
  944. * @param message a valid <em>JavaMail</em> message to be converted.
  945. * @param includeContent <code>true</code> if the <code>text</code> and
  946. * attachments of the message should also be set, otherwise
  947. * <code>false</code>.
  948. * @return message data object with the values filled out to match
  949. * the <em>JavaMail</em> object.
  950. */
  951. private MessageDO createDOFromJavaMailMessage(final MimeMessage message,
  952. final boolean includeContent)
  953. throws SystemException {
  954. // right - we got here, so that means we have a message
  955. MessageDO messageDO = new MessageDO();
  956. try {
  957. //setting the fields of the MessageDO:
  958. if (message.getFolder() != null) {
  959. messageDO.setFolderName(message.getFolder().getName());
  960. }
  961. if (message.getReceivedDate() != null) {
  962. GregorianCalendar receivedDate = new GregorianCalendar();
  963. receivedDate.setTime(message.getReceivedDate());
  964. messageDO.setReceived(receivedDate);
  965. }
  966. if (message.getRecipients(Message.RecipientType.TO) != null) {
  967. messageDO.setRecipients(Arrays.asList(toStringArray(
  968. message.getRecipients(Message.RecipientType.TO))));
  969. }
  970. if (message.getRecipients(Message.RecipientType.CC) != null) {
  971. messageDO.setRecipientsCC(Arrays.asList(toStringArray(
  972. message.getRecipients(Message.RecipientType.CC))));
  973. }
  974. if (message.getRecipients(Message.RecipientType.BCC) != null) {
  975. messageDO.setRecipientsBCC(Arrays.asList(toStringArray(
  976. message.getRecipients(Message.RecipientType.BCC))));
  977. }
  978. if (message.getFrom() != null) {
  979. messageDO.setSenders(Arrays.asList(toStringArray(
  980. message.getFrom())));
  981. }
  982. if (message.getSentDate() != null) {
  983. GregorianCalendar sentDate = new GregorianCalendar();
  984. sentDate.setTime(message.getSentDate());
  985. messageDO.setSent(sentDate);
  986. }
  987. messageDO.setSize(new Integer(message.getSize()));
  988. messageDO.setSubject(message.getSubject());
  989. // message content handling - not always done for efficiency in lists
  990. if (includeContent) {
  991. Integer format;
  992. String text;
  993. // create new, empty List for our attachments
  994. messageDO.setAttachments(new Vector());
  995. // if it is a multipart message (has attachments), pass control to
  996. // recursive routine to go thro' them all
  997. if (message.isMimeType("multipart/*")) {
  998. addMultiPart(message, messageDO);
  999. // here are types with textual content
  1000. } else if (message.isMimeType("text/*") ||
  1001. message.isMimeType("message/*")) {
  1002. // if it is not multipart, we're just left with text or HTML
  1003. if (message.isMimeType("text/HTML")) {
  1004. // simple message with HTML content
  1005. messageDO.setFormat(FormatConstants.FORMAT_HTML);
  1006. } else {
  1007. // anything else with simple content should have text content
  1008. messageDO.setFormat(FormatConstants.FORMAT_TEXT);
  1009. }
  1010. messageDO.setText((String) message.getContent());
  1011. // other (not correct?) types, as self-contained attachments...
  1012. } else {
  1013. messageDO.setFormat(FormatConstants.FORMAT_TEXT);
  1014. messageDO.setText("");
  1015. addPart(message, messageDO);
  1016. }
  1017. }
  1018. messageDO.setMessageID(message.getMessageID());
  1019. } catch (MessagingException e) {
  1020. throw new SystemException(e);
  1021. } catch (IOException e) {
  1022. throw new SystemException(e);
  1023. }
  1024. return messageDO;
  1025. }
  1026. /**
  1027. * <p>Create a new mail folder.</p>
  1028. *
  1029. * @param mailSession valid mail session to which the user should already be
  1030. * logged in.
  1031. * @param folderName the full path name of the folder to create.
  1032. *
  1033. * @ejb.interface-method
  1034. * view-type = "remote"
  1035. */
  1036. public void createFolder(final MailSession mailSession,
  1037. final String folderName)
  1038. throws SystemException {
  1039. assert (mailSession != null);
  1040. checkDateFormatter(mailSession);
  1041. Session javaMailSession;
  1042. try {
  1043. javaMailSession = mailSession.getJavaMailSession();
  1044. } catch (AuthenticationFailedException e) {
  1045. throw new SystemException(
  1046. "User is no longer authorized to use this server: " +
  1047. e.getMessage(),
  1048. e);
  1049. } catch (MessagingException e) {
  1050. throw new SystemException(e);
  1051. } catch (SecurityServerException e) {
  1052. throw new SystemException(e);
  1053. } catch (java.security.NoSuchProviderException e) {
  1054. throw new SystemException(e);
  1055. }
  1056. Store store = mailServer.connectStore(mailSession);
  1057. try {
  1058. if (folderName == null) {
  1059. throw new SystemException(
  1060. "ERROR in MailBean.createFolder: folderName is null");
  1061. }
  1062. Folder folder = mailServer.getFolder(mailSession, store, folderName);
  1063. if (!folder.create(Folder.HOLDS_MESSAGES)) {
  1064. throw new SystemException(
  1065. "ERROR in MailBean.createFolder: could not create folder '" +
  1066. folderName + "'");
  1067. }
  1068. } catch (MessagingException e) {
  1069. throw new SystemException(e);
  1070. } finally {
  1071. try {
  1072. store.close();
  1073. } catch (MessagingException e) {
  1074. logger.error("Messaging exception on closing the store", e);
  1075. }
  1076. }
  1077. }
  1078. /**
  1079. * <p>Helper method for <code>createThreadMethod</code>.</p>
  1080. *
  1081. * <p>Create a new message in the drafts folder from an existing one,
  1082. * resulting in a forwarded message.</p>
  1083. *
  1084. * @param mailSession valid mail session to which the user should already be
  1085. * logged in.
  1086. * @param folderName the name of the folder to copy existing messages from.
  1087. * @param messageIds the unique identifier of the messages to be extended.
  1088. * Can be <code>null</code> if a new message is requeested. When
  1089. * forwarding, multiple address identifiers may be specified otherwise
  1090. * (if editing a draft message or replying) only one message identifier
  1091. * should be set in the list.
  1092. * @param thread set to one of the constants in {@link MailConstants
  1093. * MailConstants}.
  1094. * @return populated message data object matching the required
  1095. * message, and with the <code>id</code> set to the message in the
  1096. * drafts folder.
  1097. */
  1098. private MimeMessage createForwardedMessage(final MailSession mailSession,
  1099. final Folder folder,
  1100. final List messageIds)
  1101. throws SystemException {
  1102. checkDateFormatter(mailSession);
  1103. try {
  1104. Session javaMailSession;
  1105. try {
  1106. javaMailSession = mailSession.getJavaMailSession();
  1107. } catch (java.security.NoSuchProviderException e1) {
  1108. throw new SystemException(e1);
  1109. }
  1110. UserDO user = mailSession.getUser();
  1111. // if this is HTML, we'll need to store multipart data
  1112. MessageTextParts messageTextParts = null;
  1113. // first go thro' all the messages and see if there are _any_ which
  1114. // are multipart
  1115. boolean isMultipart = false;
  1116. int format = FormatConstants.FORMAT_TEXT;
  1117. for (Iterator i = messageIds.iterator(); i.hasNext();) {
  1118. String id = (String) i.next();
  1119. MimeMessage oldMessage = findJavaMailMessageByFolderMessageId(folder,
  1120. id);
  1121. // is this multipart?
  1122. if (oldMessage.isMimeType("multipart/*")) {
  1123. isMultipart = true;
  1124. // try to find an HTML subpart
  1125. messageTextParts = getMultiPartText(oldMessage);
  1126. if (messageTextParts.HTMLPart != null) {
  1127. format = FormatConstants.FORMAT_HTML;
  1128. // no need to check any further...
  1129. break;
  1130. }
  1131. }
  1132. }
  1133. // text header/prefix depends on the format
  1134. String messageHeader;
  1135. if (format == FormatConstants.FORMAT_HTML) {
  1136. messageHeader = settings.getStringSetting(mailSession,
  1137. "emailHeaderForwardHTML",
  1138. user);
  1139. } else {
  1140. messageHeader = settings.getStringSetting(mailSession,
  1141. "emailHeaderForwardText",
  1142. user);
  1143. }
  1144. MimeMessage newMessage = new MimeMessage(javaMailSession);
  1145. StringBuffer subject = new StringBuffer();
  1146. String subjectPrefix = settings.getStringSetting(mailSession,
  1147. "emailSubjectForwardPrefix",
  1148. user);
  1149. String subjectSeperator = settings.getStringSetting(mailSession,
  1150. "emailSubjectForwardSeperator",
  1151. user);
  1152. subject.append(subjectPrefix);
  1153. StringBuffer messageText = new StringBuffer();
  1154. // we'll format the reply text, if it is text & this is HTML
  1155. CharacterEntityFormat characterEntities = new CharacterEntityFormat();
  1156. // go thro' all of the old ids again, this time to add the content
  1157. int index = 0;
  1158. for (Iterator i = messageIds.iterator(); i.hasNext(); ++index) {
  1159. String id = (String) i.next();
  1160. MimeMessage oldMessage = findJavaMailMessageByFolderMessageId(folder,
  1161. id);
  1162. // prepend Re: or Fwd: unless the previous subject already starts like this
  1163. String oldSubject = StringHandling.getNotNull(oldMessage.getSubject(),
  1164. getNullString());
  1165. // if there is a fwd: prefix check this message doesn't start with
  1166. // that
  1167. if ((subjectPrefix != null) &&
  1168. (oldSubject.startsWith(subjectPrefix))) {
  1169. oldSubject = oldSubject.substring(subjectPrefix.length());
  1170. }
  1171. // if there is more than one forwarded message, append separator
  1172. // between the subjects
  1173. if ((index > 0) && !oldSubject.equals("")) {
  1174. subject.append(subjectSeperator);
  1175. }
  1176. subject.append(oldSubject);
  1177. // locate the multipart in the new message, for multiparts
  1178. String oldMessageText = null;
  1179. int oldFormat = FormatCon