Adapt to changes in Argeo TP
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 4 Dec 2023 15:57:10 +0000 (16:57 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 4 Dec 2023 15:57:10 +0000 (16:57 +0100)
Makefile
org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenance.java
org.argeo.app.core/src/org/argeo/app/mail/EmailMigration.java [deleted file]
org.argeo.app.core/src/org/argeo/app/mail/EmailUtils.java [deleted file]
org.argeo.app.theme.default/OSGI-INF/cmsTheme.xml
org.argeo.app.theme.default/bnd.bnd
swt/org.argeo.app.swt/bnd.bnd
swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/BundleSvgTheme.java [new file with mode: 0644]
swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/SvgToPng.java [new file with mode: 0644]

index ad5bd8b73da21e60c8a93677da404c8e7de359b9..e724f9bd67d837362d9e34d3d1027319845897a6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -27,8 +27,11 @@ swt/org.argeo.app.ui \
 DEP_CATEGORIES = \
 org.argeo.tp \
 org.argeo.tp.httpd \
+org.argeo.tp.sys \
+org.argeo.tp.sdk \
 org.argeo.tp.jcr \
 org.argeo.tp.utils \
+org.argeo.tp.img \
 org.argeo.tp.publish \
 org.argeo.tp.math \
 org.argeo.tp.earth \
index 2104145c648d5ec2d812e4df66358b889fa70eb6..e1fb4fef92261557ad339321d0257ffe91f009f6 100644 (file)
@@ -1,14 +1,10 @@
 package org.argeo.app.core;
 
-import java.net.MalformedURLException;
-import java.net.URL;
-
 import javax.measure.Quantity;
 import javax.measure.quantity.Area;
 
-import org.argeo.api.acr.spi.ContentNamespace;
 import org.argeo.api.acr.spi.ProvidedRepository;
-import org.geotools.gml3.v3_2.GML;
+//import org.geotools.gml3.v3_2.GML;
 
 import si.uom.SI;
 import tech.units.indriya.quantity.Quantities;
@@ -31,27 +27,27 @@ public class SuiteMaintenance {
 //             }
 
                // GML schema import fails because of xlinks issues
-               getContentRepository().registerTypes(new ContentNamespace() {
-
-                       @Override
-                       public URL getSchemaResource() {
-                               try {
-                                       return new URL(GML.getInstance().getSchemaLocation());
-                               } catch (MalformedURLException e) {
-                                       throw new IllegalArgumentException(e);
-                               }
-                       }
-
-                       @Override
-                       public String getNamespaceURI() {
-                               return GML.getInstance().getNamespaceURI();
-                       }
-
-                       @Override
-                       public String getDefaultPrefix() {
-                               return "gml";
-                       }
-               });
+//             getContentRepository().registerTypes(new ContentNamespace() {
+//
+//                     @Override
+//                     public URL getSchemaResource() {
+//                             try {
+//                                     return new URL(GML.getInstance().getSchemaLocation());
+//                             } catch (MalformedURLException e) {
+//                                     throw new IllegalArgumentException(e);
+//                             }
+//                     }
+//
+//                     @Override
+//                     public String getNamespaceURI() {
+//                             return GML.getInstance().getNamespaceURI();
+//                     }
+//
+//                     @Override
+//                     public String getDefaultPrefix() {
+//                             return "gml";
+//                     }
+//             });
 
        }
 
diff --git a/org.argeo.app.core/src/org/argeo/app/mail/EmailMigration.java b/org.argeo.app.core/src/org/argeo/app/mail/EmailMigration.java
deleted file mode 100644 (file)
index 8c899c2..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-package org.argeo.app.mail;
-
-import static java.lang.System.Logger.Level.DEBUG;
-import static java.lang.System.Logger.Level.ERROR;
-import static org.argeo.app.mail.EmailUtils.describe;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.System.Logger;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.time.Instant;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Properties;
-
-import javax.mail.FetchProfile;
-import javax.mail.Folder;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Store;
-import javax.mail.URLName;
-import javax.mail.internet.InternetHeaders;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.search.HeaderTerm;
-import javax.mail.util.SharedFileInputStream;
-
-import com.sun.mail.imap.IMAPFolder;
-import com.sun.mail.mbox.MboxFolder;
-import com.sun.mail.mbox.MboxMessage;
-
-/** Migrates emails from one storage to the another one. */
-public class EmailMigration {
-       private final static Logger logger = System.getLogger(EmailMigration.class.getName());
-
-//     private String targetBaseDir;
-
-       private String sourceServer;
-       private String sourceUsername;
-       private String sourcePassword;
-
-       private String targetServer;
-       private String targetUsername;
-       private String targetPassword;
-
-       private boolean targetSupportDualTypeFolders = true;
-
-       public void process() throws MessagingException, IOException {
-//             Path baseDir = Paths.get(targetBaseDir).resolve(sourceUsername).resolve("mbox");
-
-               Store sourceStore = null;
-               try {
-                       Properties sourceProperties = System.getProperties();
-                       sourceProperties.setProperty("mail.store.protocol", "imaps");
-
-                       Session sourceSession = Session.getInstance(sourceProperties, null);
-                       // session.setDebug(true);
-                       sourceStore = sourceSession.getStore("imaps");
-                       sourceStore.connect(sourceServer, sourceUsername, sourcePassword);
-
-                       Folder defaultFolder = sourceStore.getDefaultFolder();
-//                     migrateFolders(baseDir, defaultFolder);
-
-                       // Always start with Inbox
-//                     Folder inboxFolder = sourceStore.getFolder(EmailUtils.INBOX);
-//                     migrateFolder(baseDir, inboxFolder);
-
-                       Properties targetProperties = System.getProperties();
-                       targetProperties.setProperty("mail.imap.starttls.enable", "true");
-                       targetProperties.setProperty("mail.imap.auth", "true");
-
-                       Session targetSession = Session.getInstance(targetProperties, null);
-                       // session.setDebug(true);
-                       Store targetStore = targetSession.getStore("imap");
-                       targetStore.connect(targetServer, targetUsername, targetPassword);
-
-//                     Folder targetFolder = targetStore.getFolder(EmailUtils.INBOX);
-//                     logger.log(DEBUG, "Source message count " + inboxFolder.getMessageCount());
-//                     logger.log(DEBUG, "Target message count " + targetFolder.getMessageCount());
-
-                       migrateFolders(defaultFolder, targetStore);
-               } finally {
-                       if (sourceStore != null)
-                               sourceStore.close();
-
-               }
-       }
-
-       protected void migrateFolders(Folder sourceParentFolder, Store targetStore) throws MessagingException, IOException {
-               folders: for (Folder sourceFolder : sourceParentFolder.list()) {
-                       String sourceFolderName = sourceFolder.getName();
-
-                       String sourceFolderFullName = sourceFolder.getFullName();
-                       char sourceFolderSeparator = sourceParentFolder.getSeparator();
-                       char targetFolderSeparator = targetStore.getDefaultFolder().getSeparator();
-                       String targetFolderFullName = sourceFolderFullName.replace(sourceFolderSeparator, targetFolderSeparator);
-
-                       // GMail specific
-                       if (sourceFolderFullName.equals("[Gmail]")) {
-                               migrateFolders(sourceFolder, targetStore);
-                               continue folders;
-                       }
-                       if (sourceFolderFullName.startsWith("[Gmail]")) {
-                               String subFolderName = null;
-                               // Make it configurable
-                               switch (sourceFolderName) {
-                               case "All Mail":
-                               case "Important":
-                               case "Spam":
-                                       continue folders;
-                               case "Sent Mail":
-                                       subFolderName = "Sent";
-                               default:
-                                       // does nothing
-                               }
-                               targetFolderFullName = subFolderName == null ? sourceFolder.getName() : subFolderName;
-                       }
-
-                       // nature of the source folder
-                       int messageCount = (sourceFolder.getType() & Folder.HOLDS_MESSAGES) != 0 ? sourceFolder.getMessageCount()
-                                       : 0;
-                       boolean hasSubFolders = (sourceFolder.getType() & Folder.HOLDS_FOLDERS) != 0
-                                       ? sourceFolder.list().length != 0
-                                       : false;
-
-                       Folder targetFolder;
-                       if (targetSupportDualTypeFolders) {
-                               targetFolder = targetStore.getFolder(targetFolderFullName);
-                               if (!targetFolder.exists()) {
-                                       targetFolder.create(Folder.HOLDS_FOLDERS | Folder.HOLDS_MESSAGES);
-                                       logger.log(DEBUG, "Created HOLDS_FOLDERS | HOLDS_MESSAGES folder " + targetFolder.getFullName());
-                               }
-
-                       } else {
-                               if (hasSubFolders) {// has sub-folders
-                                       if (messageCount == 0) {
-                                               targetFolder = targetStore.getFolder(targetFolderFullName);
-                                               if (!targetFolder.exists()) {
-                                                       targetFolder.create(Folder.HOLDS_FOLDERS);
-                                                       logger.log(DEBUG, "Created HOLDS_FOLDERS folder " + targetFolder.getFullName());
-                                               }
-                                       } else {// also has messages
-                                               Folder parentFolder = targetStore.getFolder(targetFolderFullName);
-                                               if (!parentFolder.exists()) {
-                                                       parentFolder.create(Folder.HOLDS_FOLDERS);
-                                                       logger.log(DEBUG, "Created HOLDS_FOLDERS folder " + parentFolder.getFullName());
-                                               }
-                                               String miscFullName = targetFolderFullName + targetFolderSeparator + "_Misc";
-                                               targetFolder = targetStore.getFolder(miscFullName);
-                                               if (!targetFolder.exists()) {
-                                                       targetFolder.create(Folder.HOLDS_MESSAGES);
-                                                       logger.log(DEBUG, "Created HOLDS_MESSAGES folder " + targetFolder.getFullName());
-                                               }
-                                       }
-                               } else {// no sub-folders
-                                       if (messageCount == 0) { // empty
-                                               logger.log(DEBUG, "Skip empty folder " + targetFolderFullName);
-                                               continue folders;
-                                       }
-                                       targetFolder = targetStore.getFolder(targetFolderFullName);
-                                       if (!targetFolder.exists()) {
-                                               targetFolder.create(Folder.HOLDS_MESSAGES);
-                                               logger.log(DEBUG, "Created HOLDS_MESSAGES folder " + targetFolder.getFullName());
-                                       }
-                               }
-                       }
-
-                       if (messageCount != 0) {
-
-                               targetFolder.open(Folder.READ_WRITE);
-                               try {
-                                       long begin = System.currentTimeMillis();
-                                       sourceFolder.open(Folder.READ_ONLY);
-                                       migrateFolder(sourceFolder, targetFolder);
-                                       long duration = System.currentTimeMillis() - begin;
-                                       logger.log(DEBUG, targetFolderFullName + " - Migration of " + messageCount + " messages took "
-                                                       + (duration / 1000) + " s (" + (duration / messageCount) + " ms per message)");
-                               } finally {
-                                       sourceFolder.close();
-                                       targetFolder.close();
-                               }
-                       }
-
-                       // recursive
-                       if (hasSubFolders) {
-                               migrateFolders(sourceFolder, targetStore);
-                       }
-               }
-       }
-
-       protected void migrateFoldersToFs(Path baseDir, Folder sourceFolder) throws MessagingException, IOException {
-               folders: for (Folder folder : sourceFolder.list()) {
-                       String folderName = folder.getName();
-
-                       if ((folder.getType() & Folder.HOLDS_MESSAGES) != 0) {
-                               // Make it configurable
-                               switch (folderName) {
-                               case "All Mail":
-                               case "Important":
-                                       continue folders;
-                               default:
-                                       // doe nothing
-                               }
-                               migrateFolderToFs(baseDir, folder);
-                       }
-                       if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) {
-                               migrateFoldersToFs(baseDir.resolve(folder.getName()), folder);
-                       }
-               }
-       }
-
-       protected void migrateFolderToFs(Path baseDir, Folder sourceFolder) throws MessagingException, IOException {
-
-               String folderName = sourceFolder.getName();
-               sourceFolder.open(Folder.READ_ONLY);
-
-               Folder targetFolder = null;
-               try {
-                       int messageCount = sourceFolder.getMessageCount();
-                       logger.log(DEBUG, folderName + " - Message count : " + messageCount);
-                       if (messageCount == 0)
-                               return;
-//                     logger.log(DEBUG, folderName + " - Unread Messages : " + sourceFolder.getUnreadMessageCount());
-
-                       boolean saveAsFiles = false;
-
-                       if (saveAsFiles) {
-                               Message messages[] = sourceFolder.getMessages();
-
-                               for (int i = 0; i < messages.length; ++i) {
-//                                     logger.log(DEBUG, "MESSAGE #" + (i + 1) + ":");
-                                       Message msg = messages[i];
-//                                     String from = "unknown";
-//                                     if (msg.getReplyTo().length >= 1) {
-//                                             from = msg.getReplyTo()[0].toString();
-//                                     } else if (msg.getFrom().length >= 1) {
-//                                             from = msg.getFrom()[0].toString();
-//                                     }
-                                       String subject = msg.getSubject();
-                                       Instant sentDate = msg.getSentDate().toInstant();
-//                                     logger.log(DEBUG, "Saving ... " + subject + " from " + from + " (" + sentDate + ")");
-                                       String fileName = sentDate + "  " + subject;
-                                       Path file = baseDir.resolve(fileName);
-                                       savePartsAsFiles(msg.getContent(), file);
-                               }
-                       } else {
-                               long begin = System.currentTimeMillis();
-                               targetFolder = openMboxTargetFolder(sourceFolder, baseDir);
-                               migrateFolder(sourceFolder, targetFolder);
-                               long duration = System.currentTimeMillis() - begin;
-                               logger.log(DEBUG, folderName + " - Migration of " + messageCount + " messages took " + (duration / 1000)
-                                               + " s (" + (duration / messageCount) + " ms per message)");
-                       }
-               } finally {
-                       sourceFolder.close();
-                       if (targetFolder != null)
-                               targetFolder.close();
-               }
-       }
-
-       protected Folder migrateFolder(Folder sourceFolder, Folder targetFolder) throws MessagingException, IOException {
-               String folderName = targetFolder.getName();
-
-               int lastSourceNumber;
-               int currentTargetMessageCount = targetFolder.getMessageCount();
-               if (currentTargetMessageCount != 0) {
-                       MimeMessage lastTargetMessage = (MimeMessage) targetFolder.getMessage(currentTargetMessageCount);
-                       logger.log(DEBUG, folderName + " - Last target message " + describe(lastTargetMessage));
-                       Date lastTargetSent = lastTargetMessage.getReceivedDate();
-                       Message[] lastSourceMessage = sourceFolder
-                                       .search(new HeaderTerm(EmailUtils.MESSAGE_ID, lastTargetMessage.getMessageID()));
-                       if (lastSourceMessage.length == 0)
-                               throw new IllegalStateException("No message found with message ID " + lastTargetMessage.getMessageID());
-                       if (lastSourceMessage.length != 1) {
-                               for (Message msg : lastSourceMessage) {
-                                       logger.log(ERROR, "Message " + describe(msg));
-
-                               }
-                               throw new IllegalStateException(
-                                               lastSourceMessage.length + " messages found with received date " + lastTargetSent.toInstant());
-                       }
-                       lastSourceNumber = lastSourceMessage[0].getMessageNumber();
-               } else {
-                       lastSourceNumber = 0;
-               }
-               logger.log(DEBUG, folderName + " - Last source message number " + lastSourceNumber);
-
-               int countToRetrieve = sourceFolder.getMessageCount() - lastSourceNumber;
-
-               FetchProfile fetchProfile = new FetchProfile();
-               fetchProfile.add(FetchProfile.Item.FLAGS);
-               fetchProfile.add(FetchProfile.Item.ENVELOPE);
-               fetchProfile.add(FetchProfile.Item.CONTENT_INFO);
-               fetchProfile.add(FetchProfile.Item.SIZE);
-               if (sourceFolder instanceof IMAPFolder) {
-                       // IMAPFolder sourceImapFolder = (IMAPFolder) sourceFolder;
-                       fetchProfile.add(IMAPFolder.FetchProfileItem.HEADERS);
-                       fetchProfile.add(IMAPFolder.FetchProfileItem.MESSAGE);
-               }
-
-               int batchSize = 100;
-               int batchCount = countToRetrieve / batchSize;
-               if (countToRetrieve % batchSize != 0)
-                       batchCount = batchCount + 1;
-               // int batchCount = 2; // for testing
-               for (int i = 0; i < batchCount; i++) {
-                       long begin = System.currentTimeMillis();
-
-                       int start = lastSourceNumber + i * batchSize + 1;
-                       int end = lastSourceNumber + (i + 1) * batchSize;
-                       if (end >= (lastSourceNumber + countToRetrieve + 1))
-                               end = lastSourceNumber + countToRetrieve;
-                       Message[] sourceMessages = sourceFolder.getMessages(start, end);
-                       sourceFolder.fetch(sourceMessages, fetchProfile);
-                       // targetFolder.appendMessages(sourceMessages);
-                       // sourceFolder.copyMessages(sourceMessages,targetFolder);
-
-                       copyMessages(sourceMessages, targetFolder);
-//                     copyMessagesToMbox(sourceMessages, targetFolder);
-
-                       String describeLast = describe(sourceMessages[sourceMessages.length - 1]);
-
-//             if (i % 10 == 9) {
-                       // free memory from fetched messages
-                       sourceFolder.close();
-                       targetFolder.close();
-
-                       sourceFolder.open(Folder.READ_ONLY);
-                       targetFolder.open(Folder.READ_WRITE);
-//                     logger.log(DEBUG, "Open/close folder in order to free memory");
-//             }
-
-                       long duration = System.currentTimeMillis() - begin;
-                       logger.log(DEBUG, folderName + " - batch " + i + " took " + (duration / 1000) + " s, "
-                                       + (duration / (end - start + 1)) + " ms per message. Last message " + describeLast);
-               }
-
-               return targetFolder;
-       }
-
-       protected Folder openMboxTargetFolder(Folder sourceFolder, Path baseDir) throws MessagingException, IOException {
-               String folderName = sourceFolder.getName();
-               if (sourceFolder.getName().equals(EmailUtils.INBOX_UPPER_CASE))
-                       folderName = EmailUtils.INBOX;// Inbox
-
-               Path targetDir = baseDir;// .resolve("mbox");
-               Files.createDirectories(targetDir);
-               Path targetPath;
-               if (((sourceFolder.getType() & Folder.HOLDS_FOLDERS) != 0) && sourceFolder.list().length != 0) {
-                       Path dir = targetDir.resolve(folderName);
-                       Files.createDirectories(dir);
-                       targetPath = dir.resolve("_Misc");
-               } else {
-                       targetPath = targetDir.resolve(folderName);
-               }
-               if (!Files.exists(targetPath))
-                       Files.createFile(targetPath);
-               URLName targetUrlName = new URLName("mbox:" + targetPath.toString());
-               Properties targetProperties = new Properties();
-               // targetProperties.setProperty("mail.mime.address.strict", "false");
-               Session targetSession = Session.getDefaultInstance(targetProperties);
-               Folder targetFolder = targetSession.getFolder(targetUrlName);
-               targetFolder.open(Folder.READ_WRITE);
-
-               return targetFolder;
-       }
-
-       protected void copyMessages(Message[] sourceMessages, Folder targetFolder) throws MessagingException {
-               targetFolder.appendMessages(sourceMessages);
-       }
-
-       protected void copyMessagesToMbox(Message[] sourceMessages, Folder targetFolder)
-                       throws MessagingException, IOException {
-               Message[] targetMessages = new Message[sourceMessages.length];
-               for (int j = 0; j < sourceMessages.length; j++) {
-                       MimeMessage sourceMm = (MimeMessage) sourceMessages[j];
-                       InternetHeaders ih = new InternetHeaders();
-                       for (Enumeration<String> e = sourceMm.getAllHeaderLines(); e.hasMoreElements();) {
-                               ih.addHeaderLine(e.nextElement());
-                       }
-                       Path tmpFileSource = Files.createTempFile("argeo-mbox-source", ".txt");
-                       Path tmpFileTarget = Files.createTempFile("argeo-mbox-target", ".txt");
-                       Files.copy(sourceMm.getRawInputStream(), tmpFileSource, StandardCopyOption.REPLACE_EXISTING);
-
-                       // we use ISO_8859_1 because it is more robust than US_ASCII with regard to
-                       // missing characters
-                       try (BufferedReader reader = Files.newBufferedReader(tmpFileSource, StandardCharsets.ISO_8859_1);
-                                       BufferedWriter writer = Files.newBufferedWriter(tmpFileTarget, StandardCharsets.ISO_8859_1);) {
-                               int lineNumber = 0;
-                               String line = null;
-                               try {
-                                       while ((line = reader.readLine()) != null) {
-                                               lineNumber++;
-                                               if (line.startsWith("From ")) {
-                                                       writer.write(">" + line);
-                                                       logger.log(DEBUG,
-                                                                       "Fix line " + lineNumber + " in " + EmailUtils.describe(sourceMm) + ": " + line);
-                                               } else {
-                                                       writer.write(line);
-                                               }
-                                               writer.newLine();
-                                       }
-                               } catch (IOException e) {
-                                       logger.log(ERROR, "Error around line " + lineNumber + " of " + tmpFileSource);
-                                       throw e;
-                               }
-                       }
-
-                       MboxMessage mboxMessage = new MboxMessage((MboxFolder) targetFolder, ih,
-                                       new SharedFileInputStream(tmpFileTarget.toFile()), sourceMm.getMessageNumber(),
-                                       EmailUtils.getUnixFrom(sourceMm), true);
-                       targetMessages[j] = mboxMessage;
-
-                       // clean up
-                       Files.delete(tmpFileSource);
-                       Files.delete(tmpFileTarget);
-               }
-               targetFolder.appendMessages(targetMessages);
-
-       }
-
-       /** Save body parts and attachments as plain files. */
-       protected void savePartsAsFiles(Object content, Path fileBase) throws IOException, MessagingException {
-               OutputStream out = null;
-               InputStream in = null;
-               try {
-                       if (content instanceof Multipart) {
-                               Multipart multi = ((Multipart) content);
-                               int parts = multi.getCount();
-                               for (int j = 0; j < parts; ++j) {
-                                       MimeBodyPart part = (MimeBodyPart) multi.getBodyPart(j);
-                                       if (part.getContent() instanceof Multipart) {
-                                               // part-within-a-part, do some recursion...
-                                               savePartsAsFiles(part.getContent(), fileBase);
-                                       } else {
-                                               String extension = "";
-                                               if (part.isMimeType("text/html")) {
-                                                       extension = "html";
-                                               } else {
-                                                       if (part.isMimeType("text/plain")) {
-                                                               extension = "txt";
-                                                       } else {
-                                                               // Try to get the name of the attachment
-                                                               extension = part.getDataHandler().getName();
-                                                       }
-                                               }
-                                               String filename = fileBase + "." + extension;
-                                               System.out.println("... " + filename);
-                                               out = new FileOutputStream(new File(filename));
-                                               in = part.getInputStream();
-                                               int k;
-                                               while ((k = in.read()) != -1) {
-                                                       out.write(k);
-                                               }
-                                       }
-                               }
-                       }
-               } finally {
-                       if (in != null) {
-                               in.close();
-                       }
-                       if (out != null) {
-                               out.flush();
-                               out.close();
-                       }
-               }
-       }
-
-       public void setSourceServer(String sourceServer) {
-               this.sourceServer = sourceServer;
-       }
-
-       public void setSourceUsername(String sourceUsername) {
-               this.sourceUsername = sourceUsername;
-       }
-
-       public void setSourcePassword(String sourcePassword) {
-               this.sourcePassword = sourcePassword;
-       }
-
-       public void setTargetServer(String targetServer) {
-               this.targetServer = targetServer;
-       }
-
-       public void setTargetUsername(String targetUsername) {
-               this.targetUsername = targetUsername;
-       }
-
-       public void setTargetPassword(String targetPassword) {
-               this.targetPassword = targetPassword;
-       }
-
-       public static void main(String args[]) throws Exception {
-               if (args.length < 6)
-                       throw new IllegalArgumentException(
-                                       "usage: <source IMAP server> <source username> <source password> <target IMAP server> <target username> <target password>");
-               String sourceServer = args[0];
-               String sourceUsername = args[1];
-               String sourcePassword = args[2];
-               String targetServer = args[3];
-               String targetUsername = args[4];
-               String targetPassword = args[5];
-
-               EmailMigration emailMigration = new EmailMigration();
-               emailMigration.setSourceServer(sourceServer);
-               emailMigration.setSourceUsername(sourceUsername);
-               emailMigration.setSourcePassword(sourcePassword);
-               emailMigration.setTargetServer(targetServer);
-               emailMigration.setTargetUsername(targetUsername);
-               emailMigration.setTargetPassword(targetPassword);
-
-               emailMigration.process();
-       }
-}
diff --git a/org.argeo.app.core/src/org/argeo/app/mail/EmailUtils.java b/org.argeo.app.core/src/org/argeo/app/mail/EmailUtils.java
deleted file mode 100644 (file)
index 694c17c..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.argeo.app.mail;
-
-import java.util.Date;
-
-import javax.mail.Address;
-import javax.mail.Flags;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-
-/** Utilities around emails. */
-public class EmailUtils {
-       public final static String INBOX = "Inbox";
-       public final static String INBOX_UPPER_CASE = "INBOX";
-       public final static String MESSAGE_ID = "Message-ID";
-
-       public static String getMessageId(Message msg) {
-               try {
-                       return msg instanceof MimeMessage ? ((MimeMessage) msg).getMessageID() : "<N/A>";
-               } catch (MessagingException e) {
-                       throw new IllegalStateException("Cannot extract message id from " + msg, e);
-               }
-       }
-
-       public static String describe(Message msg) {
-               try {
-                       return "Message " + msg.getMessageNumber() + " " + msg.getSentDate().toInstant() + " " + getMessageId(msg);
-               } catch (MessagingException e) {
-                       throw new IllegalStateException("Cannot describe " + msg, e);
-               }
-       }
-
-       static void setHeadersFromFlags(MimeMessage msg, Flags flags) {
-               try {
-                       StringBuilder status = new StringBuilder();
-                       if (flags.contains(Flags.Flag.SEEN))
-                               status.append('R');
-                       if (!flags.contains(Flags.Flag.RECENT))
-                               status.append('O');
-                       if (status.length() > 0)
-                               msg.setHeader("Status", status.toString());
-                       else
-                               msg.removeHeader("Status");
-
-                       boolean sims = false;
-                       String s = msg.getHeader("X-Status", null);
-                       // is it a SIMS 2.0 format X-Status header?
-                       sims = s != null && s.length() == 4 && s.indexOf('$') >= 0;
-                       //status.setLength(0);
-                       if (flags.contains(Flags.Flag.DELETED))
-                               status.append('D');
-                       else if (sims)
-                               status.append('$');
-                       if (flags.contains(Flags.Flag.FLAGGED))
-                               status.append('F');
-                       else if (sims)
-                               status.append('$');
-                       if (flags.contains(Flags.Flag.ANSWERED))
-                               status.append('A');
-                       else if (sims)
-                               status.append('$');
-                       if (flags.contains(Flags.Flag.DRAFT))
-                               status.append('T');
-                       else if (sims)
-                               status.append('$');
-                       if (status.length() > 0)
-                               msg.setHeader("X-Status", status.toString());
-                       else
-                               msg.removeHeader("X-Status");
-
-                       String[] userFlags = flags.getUserFlags();
-                       if (userFlags.length > 0) {
-                               status.setLength(0);
-                               for (int i = 0; i < userFlags.length; i++)
-                                       status.append(userFlags[i]).append(' ');
-                               status.setLength(status.length() - 1); // smash trailing space
-                               msg.setHeader("X-Keywords", status.toString());
-                       }
-                       if (flags.contains(Flags.Flag.DELETED)) {
-                               s = msg.getHeader("X-Dt-Delete-Time", null);
-                               if (s == null)
-                                       // XXX - should be time
-                                       msg.setHeader("X-Dt-Delete-Time", "1");
-                       }
-               } catch (MessagingException e) {
-                       // ignore it
-               }
-       }
-
-    protected static String getUnixFrom(MimeMessage msg) {
-       Address[] afrom;
-       String from;
-       Date ddate;
-       String date;
-       try {
-           if ((afrom = msg.getFrom()) == null ||
-                   !(afrom[0] instanceof InternetAddress) ||
-                   (from = ((InternetAddress)afrom[0]).getAddress()) == null)
-               from = "UNKNOWN";
-           if ((ddate = msg.getReceivedDate()) == null ||
-                   (ddate = msg.getSentDate()) == null)
-               ddate = new Date();
-       } catch (MessagingException e) {
-           from = "UNKNOWN";
-           ddate = new Date();
-       }
-       date = ddate.toString();
-       // date is of the form "Sat Aug 12 02:30:00 PDT 1995"
-       // need to strip out the timezone
-       return "From " + from + " " +
-               date.substring(0, 20) + date.substring(24);
-    }
-
-       /** Singleton. */
-       private EmailUtils() {
-       }
-}
index bcb5ecb919d822b2d4ced8785344fa28e35a7fb8..28ef00fe2fb5d8f230bd227f94e6c6c037055550 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite Default Theme">
-   <implementation class="org.argeo.cms.swt.osgi.BundleSvgTheme"/>
+   <implementation class="org.argeo.app.swt.osgi.BundleSvgTheme"/>
    <service>
       <provide interface="org.argeo.api.cms.ux.CmsTheme"/>
    </service>
index 4743076885abadb13bd1f7be8cd791d4eafec12e..48ad7e2fd0d8baff418268eea4d6c20294460881 100644 (file)
@@ -6,6 +6,6 @@ Private-Package: *
 Export-Package: !*
 
 Import-Package:\
-org.argeo.cms.swt.osgi;resolution:="optional",\
+org.argeo.app.swt.osgi;resolution:="optional",\
 javax.servlet.*;version="[3,5)",\
 *
\ No newline at end of file
index fac182d3766957bad6fb7960f346fe29d27dc2aa..21c1d25740ed9022c1c6485645d5ca76efe6e085 100644 (file)
@@ -3,4 +3,5 @@ org.eclipse.swt,\
 org.argeo.api.cms.ux,\
 org.argeo.cms.ux.acr,\
 org.argeo.app.api,\
+org.argeo.cms.osgi,\
 *
\ No newline at end of file
diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/BundleSvgTheme.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/BundleSvgTheme.java
new file mode 100644 (file)
index 0000000..15a18ae
--- /dev/null
@@ -0,0 +1,131 @@
+package org.argeo.app.swt.osgi;
+
+import java.awt.Color;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.ImageTranscoder;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.argeo.cms.swt.osgi.BundleCmsSwtTheme;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.BundleContext;
+
+/** Theme which can dynamically create icons from SVG data. */
+public class BundleSvgTheme extends BundleCmsSwtTheme {
+       private final static Logger logger = System.getLogger(BundleSvgTheme.class.getName());
+
+       private Map<String, Map<Integer, ImageData>> imageDataCache = Collections.synchronizedMap(new HashMap<>());
+
+       private Map<Integer, ImageTranscoder> transcoders = Collections.synchronizedMap(new HashMap<>());
+
+       private final static String IMAGE_CACHE_KEY = BundleSvgTheme.class.getName() + ".imageCache";
+
+       @Override
+       public Image getIcon(String name, Integer preferredSize) {
+               String path = "icons/types/svg/" + name + ".svg";
+               return createImageFromSvg(path, preferredSize);
+       }
+
+       @SuppressWarnings("unchecked")
+       protected Image createImageFromSvg(String path, Integer preferredSize) {
+               Display display = Display.getCurrent();
+               Objects.requireNonNull(display, "Not a user interface thread");
+
+               Map<String, Map<Integer, Image>> imageCache = (Map<String, Map<Integer, Image>>) display
+                               .getData(IMAGE_CACHE_KEY);
+               if (imageCache == null)
+                       display.setData(IMAGE_CACHE_KEY, new HashMap<String, Map<Integer, Image>>());
+               imageCache = (Map<String, Map<Integer, Image>>) display.getData(IMAGE_CACHE_KEY);
+
+               Image image = null;
+               if (imageCache.containsKey(path)) {
+                       image = imageCache.get(path).get(preferredSize);
+               }
+               if (image != null)
+                       return image;
+               ImageData imageData = loadFromSvg(path, preferredSize);
+               image = new Image(display, imageData);
+               if (!imageCache.containsKey(path))
+                       imageCache.put(path, Collections.synchronizedMap(new HashMap<>()));
+               imageCache.get(path).put(preferredSize, image);
+               return image;
+       }
+
+       protected ImageData loadFromSvg(String path, int size) {
+               ImageData imageData = null;
+               if (imageDataCache.containsKey(path))
+                       imageData = imageDataCache.get(path).get(size);
+               if (imageData != null)
+                       return imageData;
+
+               ImageTranscoder transcoder = null;
+               synchronized (this) {
+                       transcoder = transcoders.get(size);
+                       if (transcoder == null) {
+                               transcoder = new PNGTranscoder();
+                               transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) size);
+                               transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) size);
+                               transcoder.addTranscodingHint(PNGTranscoder.KEY_BACKGROUND_COLOR, new Color(255, 255, 255, 0));
+                               transcoders.put(size, transcoder);
+                       }
+               }
+               try (InputStream in = getResourceAsStream(path); ByteArrayOutputStream out = new ByteArrayOutputStream();) {
+                       if (in == null)
+                               throw new IllegalArgumentException(path + " not found");
+                       TranscoderInput input = new TranscoderInput(in);
+                       TranscoderOutput output = new TranscoderOutput(out);
+                       transcoder.transcode(input, output);
+                       try (InputStream imageIn = new ByteArrayInputStream(out.toByteArray())) {
+                               imageData = new ImageData(imageIn);
+                       }
+                       logger.log(Level.DEBUG, () -> "Generated " + size + "x" + size + " PNG icon from " + path);
+               } catch (IOException | TranscoderException e) {
+                       throw new RuntimeException("Cannot transcode SVG " + path, e);
+               }
+
+               // cache it
+               if (!imageDataCache.containsKey(path))
+                       imageDataCache.put(path, Collections.synchronizedMap(new HashMap<>()));
+               imageDataCache.get(path).put(size, imageData);
+
+               return imageData;
+       }
+
+       @Override
+       public void init(BundleContext bundleContext, Map<String, String> properties) {
+               super.init(bundleContext, properties);
+
+               // preload all icons
+//             paths: for (String p : getImagesPaths()) {
+//                     if (!p.endsWith(".svg"))
+//                             continue paths;
+//                     createImageFromSvg(p, getDefaultIconSize());
+//             }
+       }
+
+//     @Override
+//     public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+//             Display display = Display.getDefault();
+//             if (display != null)
+//                     for (String path : imageCache.keySet()) {
+//                             for (Image image : imageCache.get(path).values()) {
+//                                     display.syncExec(() -> image.dispose());
+//                             }
+//                     }
+//             super.destroy(bundleContext, properties);
+//     }
+
+}
diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/SvgToPng.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/SvgToPng.java
new file mode 100644 (file)
index 0000000..236dbc6
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.app.swt.osgi;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.ImageTranscoder;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+
+public class SvgToPng {
+
+       public void convertSvgDir(Path sourceDir, Path targetDir, int width) {
+               System.out.println("##\n## " + width + "px - " + sourceDir + "\n##");
+               try {
+                       if (targetDir == null)
+                               targetDir = sourceDir.getParent().resolve(Integer.toString(width));
+                       Files.createDirectories(targetDir);
+
+                       PNGTranscoder transcoder = new PNGTranscoder();
+                       // transcoder.addTranscodingHint(ImageTranscoder.KEY_BACKGROUND_COLOR,
+                       // Color.WHITE);
+                       transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) width);
+                       transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) width);
+
+                       for (Path source : Files.newDirectoryStream(sourceDir, "*.svg")) {
+                               // FIXME extract base name
+                               String baseName = null; // = FilenameUtils.getBaseName(source.toString());
+                               Path target = targetDir.resolve(baseName + ".png");
+                               convertSvgFile(transcoder, source, target);
+                       }
+               } catch (IOException | TranscoderException e) {
+                       throw new IllegalStateException("Cannot convert from " + sourceDir + " to " + targetDir, e);
+               }
+
+       }
+
+       protected void convertSvgFile(ImageTranscoder transcoder, Path source, Path target)
+                       throws IOException, TranscoderException {
+               try (Reader reader = Files.newBufferedReader(source); OutputStream out = Files.newOutputStream(target);) {
+                       TranscoderInput input = new TranscoderInput(reader);
+//                     BufferedImage image = transcoder.createImage(32, 32);
+                       TranscoderOutput output = new TranscoderOutput(out);
+                       transcoder.transcode(input, output);
+                       System.out.println(source.getFileName() + " -> " + target);
+               }
+       }
+
+       public static void main(String[] args) throws Exception {
+
+               Path path = Paths.get(args[0]);
+
+               SvgToPng svgToPng = new SvgToPng();
+               svgToPng.convertSvgDir(path, null, 16);
+               svgToPng.convertSvgDir(path, null, 32);
+               svgToPng.convertSvgDir(path, null, 64);
+               svgToPng.convertSvgDir(path, null, 96);
+       }
+}