Changeset 1504 for trunk/src/org/expeditee/auth/mail/gui/MailBay.java
- Timestamp:
- 01/29/20 13:20:24 (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/expeditee/auth/mail/gui/MailBay.java
r1376 r1504 4 4 import java.nio.file.Path; 5 5 import java.nio.file.Paths; 6 import java.util.LinkedList; 6 import java.util.ArrayList; 7 import java.util.Base64; 8 import java.util.HashMap; 7 9 import java.util.List; 8 10 import java.util.Map; 9 11 import java.util.Scanner; 10 12 13 import javax.crypto.SecretKey; 14 11 15 import org.expeditee.auth.AuthenticatorBrowser; 16 import org.expeditee.auth.mail.Mail; 17 import org.expeditee.auth.mail.Mail.MailEntry; 12 18 import org.expeditee.core.Clip; 13 19 import org.expeditee.core.Colour; … … 15 21 import org.expeditee.core.Font; 16 22 import org.expeditee.core.Image; 23 import org.expeditee.encryption.Actions; 17 24 import org.expeditee.gio.EcosystemManager; 18 25 import org.expeditee.gio.GraphicsManager; … … 24 31 import org.expeditee.items.Item; 25 32 import org.expeditee.items.Text; 26 import org.expeditee.settings.UserSettings;27 33 28 34 public class MailBay { 35 // Frameset name for mail 29 36 public static final String EXPEDITEE_MAIL_FRAMESET_NAME = "expediteemail"; 30 31 / ** The y position of the header to the mail bay. */32 private static final int HEADER_OFFSET_Y = 15;33 34 / ** Space between mail messages */37 38 // Font used for messages in the MailBay 39 private static final Font MESSAGE_FONT = new Font("Serif-Plain-16"); 40 41 // Bay preview area constants. 35 42 private static final int SPACING = 25; 36 37 /** The (x,y) of the top message. */ 38 private static final int MESSAGE_OFFSET_Y = 15 + SPACING; 43 private static final int OFFSET_Y = 15; 39 44 private static final int OFFSET_X = 20; 40 41 /** Buffer image of the mail window. */ 42 private static Image _mailBuffer; 43 44 /** The list of messages shown in the mail bay. */ 45 private static List<Item> _previewMessages = new LinkedList<Item>(); 46 private static List<Item> _messages = new LinkedList<Item>(); 47 48 /** Font used for mail messages. */ 49 private static Font _messageFont = new Font("Serif-Plain-16"); 50 51 /** Used to number messages. */ 52 private static int _messageCount; 53 54 /** Creator for creating the mail frames. */ 55 private static FrameCreator _creator = null; 56 57 /** The currently logged in user, consulted when deciding if a new FrameCreator is needed. */ 58 private static String _forUser = UserSettings.UserName.get(); 59 60 /** The link that the preview pane displays pointing towards unprocessed messages. */ 61 private static Text _mailLink = new Text(-2, "@Mail", Colour.BLACK, Colour.WHITE); 62 63 /** Wether the link has been drawn before. */ 64 private static boolean isLinkInitialized = false; 65 66 /** The position of the mail link. */ 67 private static int MAIL_LINK_Y_OFFSET = 100; 68 private static int MAIL_LINK_X = 50; 69 70 /** 71 * Obtain the two messages shown at the bottom of the screen as a preview to the entire collection of mail. 72 * @return 73 */ 74 public static List<Item> getPreviewMessages() { 75 return _previewMessages; 76 } 77 78 /** 79 * An item is a 'preview mail item' if it is currently being previewed at the bottom of the screen. 80 * @param i 81 * @return 82 */ 83 public static boolean isPreviewMailItem(Item i) { 84 return _previewMessages.contains(i) || i == _mailLink; 85 } 86 87 public static void disconnect() { 88 if (_forUser != UserSettings.UserName.get()) { 89 _creator = null; 90 _forUser = UserSettings.UserName.get(); 91 } 92 } 93 94 /** 95 * Adds a message to the MailBay. 96 * @param message The basic text of the message, what is displayed in the bay window down the bottom. 97 * @options A map describing the buttons to be provided as reply options (Button Text, Action to run) 98 * @return 99 */ 100 public synchronized static Text addMessage(String timestamp, String sender, String message, String message2, Map<String, String> options) { 45 46 private static final int MAIL_LINK_X = 50; 47 48 private static List<Item> previewMessages = new ArrayList<Item>(); 49 private static FrameCreator creator; 50 private static Mail mail; 51 private static Text mailLink; 52 private static Text checkMailAction; 53 54 private static Image mailBufferImage; 55 56 public static Mail getMailClient() { 57 return mail; 58 } 59 60 public static Mail getMailClient(String user) { 61 boolean restore = mail != null; 62 String oldUser = restore ? mail.getUser() : null; 63 MailBay.reconnectToUser(user); 64 Mail ret = mail; 65 if (restore) { 66 MailBay.reconnectToUser(oldUser); 67 } 68 return ret; 69 } 70 71 public static List<Item> getPreviewMessages() { 72 return previewMessages; 73 } 74 75 public static boolean isPreviewMailItem(Item i) { 76 return previewMessages.contains(i) || i == getMailLink() || i == checkMailAction; 77 } 78 79 public static Image getImage(Clip clip, Dimension size) { 80 // Can't get an image with an invalid size 81 if (size == null || size.width <= 0 || size.height <= 0) { 82 return null; 83 } 84 85 // Update the buffer 86 updateBuffer(Item.DEFAULT_BACKGROUND, clip, size); 87 88 // Return the image buffer 89 return mailBufferImage; 90 } 91 92 public static Item getMailLink() { 93 return mailLink; 94 } 95 96 public static Item getCheckMailAction() { 97 return checkMailAction; 98 } 99 100 public static void reconnectToUser(String user) { 101 mail = new Mail(user); 102 creator = new FrameCreator(EXPEDITEE_MAIL_FRAMESET_NAME, FrameIO.MAIL_PATH, 103 EXPEDITEE_MAIL_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.AppendAfterLastItem, 104 false, AuthenticatorBrowser.PROFILEENCRYPTIONLABEL); 105 updateLink(); 106 } 107 108 public static void checkMail() { 101 109 // Invalidate whole area 102 110 DisplayController.invalidateArea(DisplayController.getMessageBayPaintArea()); 103 104 // Ensure frame creator 105 if (_creator == null || _forUser != UserSettings.UserName.get()) { 106 _forUser = UserSettings.UserName.get(); 107 _creator = new FrameCreator(EXPEDITEE_MAIL_FRAMESET_NAME, FrameIO.MAIL_PATH, EXPEDITEE_MAIL_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.AppendAfterLastItem, false, AuthenticatorBrowser.PROFILEENCRYPTIONLABEL); 108 } 109 110 // We have enough space for the header + 2 preview messages 111 if (_previewMessages.size() >= 2) { 112 _previewMessages.remove(0); 113 for (Item i : _previewMessages) { 114 i.setY(i.getY() - SPACING); 115 } 116 } 117 118 // Add new message 119 Mail mail = new Mail(message, message2, options); 120 Text t = mail.getPreviewMessage(true); 121 _messages.add(t); 122 Text header = _creator.addText(timestamp + " (From: " + sender + ")", Colour.BLACK, null, null, false); 111 previewMessages.clear(); 112 113 // Get new mail since last time we checked for mail 114 List<MailEntry> newMail = mail.checkMail(); 115 116 // Place up to two previews 117 Map<String, Integer> countBySender = countBySender(newMail); 118 String[] senders = countBySender.keySet().toArray(new String[] {}); 119 for (int i = 0; i < senders.length && i < 3; i++) { 120 String sender = senders[i]; 121 Text text = new Text("You have received " + countBySender.get(sender) + " new messages from " + sender); 122 text.setFont(MESSAGE_FONT); 123 text.setPosition(MAIL_LINK_X, OFFSET_Y + (SPACING * (i + 1))); 124 previewMessages.add(text); 125 } 126 127 // Add new mail to creator 128 for (MailEntry mail: newMail) { 129 String timestamp = mail.getTimestamp(); 130 String sender = mail.getSender(); 131 generateMailHeader(timestamp, sender); 132 creator.addText("Subject: " + mail.getSubject(), Colour.BLACK, null, null, false).setFont(MESSAGE_FONT); 133 creator.addText(mail.getMessage(), Colour.BLACK, null, null, false).setFont(MESSAGE_FONT); 134 Map<String, String> optionsTextActionMap = mail.getOptionsTextActionMap(); 135 String[] optionsTextActionMapKeyset = optionsTextActionMap.keySet().toArray(new String[] {}); 136 for (int i = 0; i < optionsTextActionMapKeyset.length; i++) { 137 String text = optionsTextActionMapKeyset[i]; 138 String[] split = text.split(":::"); 139 String action = optionsTextActionMap.get(text); 140 Text t = new Text(split[0]); 141 for (int o = 1; o < split.length; o++) { 142 t.addToData(split[o]); 143 } 144 int y = OFFSET_Y + (previewMessages.size() + i) * SPACING; 145 t.setPosition(OFFSET_X, y); 146 t.setColor(Colour.BLUE); 147 t.setFont(MESSAGE_FONT); 148 t.setAction(action); 149 creator.addItem(t, false); 150 } 151 } 152 153 DisplayController.requestRefresh(true); 154 } 155 156 public static void decryptOneOffSecureMessage(SecretKey key, List<String> data) { 157 byte[] subjectBytes = Base64.getDecoder().decode(data.get(3)); 158 String subject = new String(Actions.DecryptSymmetric(subjectBytes, key)); 159 byte[] messageBytes = Base64.getDecoder().decode(data.get(4)); 160 String message = new String(Actions.DecryptSymmetric(messageBytes, key)); 161 162 creator.addText(data.get(0) + " (Single-use encrypted message)", Colour.BLACK, null, null, false); 163 creator.addText(subject, Colour.BLACK, null, null, false).setFont(MESSAGE_FONT); 164 creator.addText(message, Colour.BLACK, null, null, false).setFont(MESSAGE_FONT); 165 166 for (int i = 5; i < data.size(); i += 2) { 167 byte[] optionKeyBytes = Base64.getDecoder().decode(data.get(i)); 168 String k = new String(org.expeditee.encryption.Actions.DecryptSymmetric(optionKeyBytes, key)); 169 byte[] optionValueBytes = Base64.getDecoder().decode(data.get(i + 1)); 170 String v = new String(org.expeditee.encryption.Actions.DecryptSymmetric(optionValueBytes, key)); 171 creator.addText(k, Colour.BLACK, null, v, false).setFont(MESSAGE_FONT); 172 } 173 } 174 175 private static void generateMailHeader(String timestamp, String sender) { 176 Text header = creator.addText(timestamp + " (From: " + sender + ")", Colour.BLACK, null, null, false); 123 177 Path credentialsFilePath = Paths.get(FrameIO.CONTACTS_PATH).resolve(sender + "-credentials").resolve("credentials.inf"); 124 178 if (credentialsFilePath.toFile().exists()) { … … 131 185 } 132 186 } 133 for (Text line: mail.getMessage()) { 134 _creator.addItem(line.copy(), false); 135 } 136 t.setLink(_creator.getCurrentFrame().getName()); 137 _previewMessages.add(t); 138 _creator.addSpace(SPACING); 139 _creator.save(); 140 141 // Make sure the link points to the latest frame 142 _mailLink.setLink(_creator.getCurrent()); 143 144 DisplayController.requestRefresh(true); 145 146 return t; 147 } 148 149 /** 150 * Obtains the image item that is drawn to display the mail bay. 151 * @param clip 152 * @param size 153 * @return 154 */ 155 public static Image getImage(Clip clip, Dimension size) { 156 // Can't get an image with an invalid size 157 if (size == null || size.width <= 0 || size.height <= 0) { 158 return null; 159 } 160 161 // Update the buffer 162 updateBuffer(Item.DEFAULT_BACKGROUND, clip, size); 163 164 // Return the image buffer 165 return _mailBuffer; 166 } 167 168 public static void clear() { 169 getPreviewMessages().clear(); 170 _messageCount = 0; 171 } 172 173 public static Item getMailLink() { 174 return _mailLink; 175 } 176 177 public static void ensureLink() { 178 if (_mailLink.getLink() == null && FrameIO.canAccessFrame(MailBay.EXPEDITEE_MAIL_FRAMESET_NAME + 1)) { 179 _mailLink.setLink(MailBay.EXPEDITEE_MAIL_FRAMESET_NAME + 1); 180 } 181 } 182 183 /** Updates the image buffer to reflect the current state of the mail bay. */ 187 } 188 184 189 private synchronized static void updateBuffer(Colour background, Clip clip, Dimension size) { 185 190 // If the buffer doesn't exist or is the wrong size, recreate it 186 if ( _mailBuffer == null || !_mailBuffer.getSize().equals(size)) {187 _mailBuffer= Image.createImage(size, true);191 if (mailBufferImage == null || !mailBufferImage.getSize().equals(size)) { 192 mailBufferImage = Image.createImage(size, true); 188 193 clip = null; // Need to recreate the entire image; 189 194 updateSize(); … … 192 197 // Prepare graphics 193 198 GraphicsManager g = EcosystemManager.getGraphicsManager(); 194 g.pushDrawingSurface( _mailBuffer);199 g.pushDrawingSurface(mailBufferImage); 195 200 if (clip != null) { 196 201 g.pushClip(clip); … … 198 203 g.setAntialiasing(true); 199 204 g.clear(background); 200 g.setFont( _messageFont);205 g.setFont(MESSAGE_FONT); 201 206 202 207 // Paint header 203 FrameGraphics.PaintItem(getHeader( Colour.BLACK));204 205 // Paint the mail messages to the screen (preview)206 for (Item message : _previewMessages) {207 if (message != null) {208 if (clip == null || clip.isNotClipped() || message.isInDrawingArea(clip.getBounds())) {209 FrameGraphics.PaintItem(message);210 }208 FrameGraphics.PaintItem(getHeader()); 209 210 // Paint the mail messages to the bay 211 for (Item message: previewMessages) { 212 if (message == null) { continue; } 213 214 if (clip == null || clip.isNotClipped() || message.isInDrawingArea(clip.getBounds())) { 215 FrameGraphics.PaintItem(message); 211 216 } 212 217 } … … 219 224 220 225 // Paint the link to the mail frame 221 if (clip == null || clip.isNotClipped() || _mailLink.isInDrawingArea(clip.getBounds())) { 222 FrameGraphics.PaintItem(_mailLink); 226 if (clip == null || clip.isNotClipped() || mailLink.isInDrawingArea(clip.getBounds())) { 227 FrameGraphics.PaintItem(mailLink); 228 } 229 230 // Paint the action item to check for new mail 231 if (clip == null || clip.isNotClipped() || checkMailAction.isInDrawingArea(clip.getBounds())) { 232 FrameGraphics.PaintItem(checkMailAction); 223 233 } 224 234 … … 226 236 } 227 237 228 /** Syncs message bay size according to FrameGraphics max size. */229 238 private static void updateSize() { 230 for (Item i : _previewMessages) {239 for (Item i: previewMessages) { 231 240 if (i != null) { 232 241 i.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); … … 234 243 } 235 244 236 _mailLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY());237 245 updateLink(); 238 246 } 239 247 240 248 private static void updateLink() { 241 if (!isLinkInitialized && DisplayController.getFramePaintArea() != null 242 && DisplayController.getFramePaintAreaWidth() > 0) { 243 // set up 'Messages' link on the right hand side 244 _mailLink.setPosition(DisplayController.getMessageBayPaintArea().getWidth() - MAIL_LINK_Y_OFFSET, 245 MAIL_LINK_X); 246 _mailLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); 247 isLinkInitialized = true; 248 } else { 249 _mailLink.setPosition(DisplayController.getMessageBayPaintArea().getWidth() - MAIL_LINK_Y_OFFSET, 250 MAIL_LINK_X); 251 } 252 } 253 254 private static Text getHeader(Colour fontColor) { 255 Text t = new Text("You have [" + _messages.size() + "] unprocessed messages waiting."); 256 if (_messages.size() >= 2) { 257 t.setText(t.getText() + " Two latest below:"); 258 } 259 t.setPosition(OFFSET_X, HEADER_OFFSET_Y); 260 t.setOffset(0, -DisplayController.getFramePaintAreaHeight()); 261 t.setColor(fontColor); 262 t.setFont(_messageFont.clone()); 263 return t; 264 } 265 266 private static String getMessagePrefix() { 267 _messageCount++; 268 return "@" + _messageCount + ": "; 269 } 270 271 private static class Mail { 272 private String message; 273 private Map<String, String> options; 274 private String message2; 275 276 private Mail(String message, String message2, Map<String, String> options) { 277 this.message = message; 278 this.message2 = message2; 279 this.options = options; 280 } 281 282 private Text getPreviewMessage(boolean usePrefix) { 283 Text t = usePrefix ? new Text(getMessagePrefix() + message) : new Text(message); 284 int y = MESSAGE_OFFSET_Y + _previewMessages.size() * SPACING; 285 t.setPosition(OFFSET_X, y); 286 t.setColor(Colour.BLACK); 287 t.setFont(_messageFont.clone()); 288 return t; 289 } 290 291 private Text getDetailLine() { 292 if (message2 == null || message2.isEmpty()) { 293 return null; 294 } 295 Text t = new Text(message2); 296 int y = MESSAGE_OFFSET_Y + _previewMessages.size() * SPACING; 297 t.setPosition(OFFSET_X, y); 298 t.setColor(Colour.BLACK); 299 t.setFont(_messageFont.clone()); 300 return t; 301 } 302 303 private Text[] getMessage() { 304 List<Text> items = new LinkedList<Text>(); 305 items.add(getPreviewMessage(false)); 306 Text detail = getDetailLine(); 307 if (detail != null) { 308 items.add(detail); 249 mailLink = new Text(-2, "See Mail", Colour.BLACK, Colour.WHITE); 250 mailLink.setFont(MESSAGE_FONT); 251 mailLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); 252 mailLink.setAnchorRight(OFFSET_X); 253 mailLink.setAnchorTop(OFFSET_Y); 254 mailLink.setLink(creator.getCurrent()); 255 256 checkMailAction = new Text(-2, "Get New Mail", Colour.BLACK, Colour.WHITE); 257 checkMailAction.setFont(MESSAGE_FONT); 258 checkMailAction.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); 259 checkMailAction.setAnchorRight(OFFSET_X); 260 checkMailAction.setAnchorTop(OFFSET_Y + SPACING); 261 checkMailAction.setAction("CheckForNewMail"); 262 } 263 264 private static Text getHeader() { 265 Text header = new Text("You have [" + previewMessages.size() + "] new messages since last you check."); 266 header.setPosition(OFFSET_X, OFFSET_Y); 267 header.setOffset(0, -DisplayController.getFramePaintAreaHeight()); 268 header.setFont(MESSAGE_FONT); 269 return header; 270 } 271 272 private static Map<String, Integer> countBySender(List<MailEntry> newMail) { 273 Map<String, Integer> bySenderCount = new HashMap<String, Integer>(); 274 275 for (MailEntry mail: newMail) { 276 String sender = mail.getSender(); 277 if (mail.isSingleUseEncryption()) { 278 sender = "Encrypted Sender"; 309 279 } 310 280 311 int i = items.size(); 312 for (String content: options.keySet()) { 313 String[] split = content.split(":::"); 314 String action = options.get(content); 315 Text t = new Text(split[0]); 316 for (int o = 1; o < split.length; o++) { 317 t.addToData(split[o]); 318 } 319 int y = MESSAGE_OFFSET_Y + (_previewMessages.size() + i) * SPACING; 320 t.setPosition(OFFSET_X, y); 321 t.setColor(Colour.BLUE); 322 t.setFont(_messageFont.clone()); 323 t.setAction(action); 324 items.add(t); 325 i++; 326 } 327 328 return items.toArray(new Text[] {}); 329 } 281 if (bySenderCount.containsKey(sender)) { 282 Integer newValue = bySenderCount.get(sender) + 1; 283 bySenderCount.put(sender, newValue); 284 } else { 285 bySenderCount.put(sender, 1); 286 } 287 } 288 289 return bySenderCount; 330 290 } 331 291 }
Note:
See TracChangeset
for help on using the changeset viewer.