Ignore:
Timestamp:
01/29/20 13:20:24 (4 years ago)
Author:
bnemhaus
Message:

Revised implementation of authenticated Expeditee mail. Motivated by bugs relating to messages not being marked as read and incorrect counting of new messages for users, the Expeditee mail system has been rewritten. The new code not only does not exhibit the previous bugs but is also better engineered. Whilst the MailBay is static (which is in line with the MessageBay), the Mail class is no longer static and must be initialised for each user as they log in.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/auth/AuthenticatorBrowser.java

    r1453 r1504  
    22
    33import java.io.File;
    4 import java.io.FileFilter;
    54import java.io.FileInputStream;
    65import java.io.FileNotFoundException;
    76import java.io.FileOutputStream;
    8 import java.io.FileWriter;
    97import java.io.IOException;
    108import java.io.InputStream;
    11 import java.nio.file.Path;
    129import java.nio.file.Paths;
    1310import java.security.KeyFactory;
     
    2219import java.security.spec.InvalidKeySpecException;
    2320import java.security.spec.X509EncodedKeySpec;
    24 import java.sql.Connection;
    25 import java.sql.DriverManager;
    26 import java.sql.PreparedStatement;
    27 import java.sql.ResultSet;
    2821import java.sql.SQLException;
    29 import java.text.ParseException;
    30 import java.text.SimpleDateFormat;
    3122import java.util.Arrays;
    3223import java.util.Base64;
    3324import java.util.Collection;
    34 import java.util.Date;
    35 import java.util.HashMap;
    36 import java.util.HashSet;
    37 import java.util.Map;
    3825import java.util.Scanner;
    39 import java.util.Set;
    4026import java.util.stream.Stream;
    4127
     
    4430
    4531import org.expeditee.actions.Actions;
    46 import org.expeditee.auth.mail.Mail;
    4732import org.expeditee.core.Dimension;
    4833import org.expeditee.core.Point;
     
    6752import org.expeditee.settings.UserSettings;
    6853import org.expeditee.settings.identity.secrets.KeyList;
    69 import org.expeditee.stats.Formatter;
    7054
    7155public final class AuthenticatorBrowser extends Browser implements CryptographyConstants {
     
    195179                        }
    196180                }
    197         }
    198        
    199         final void loadMailFromFile(Path dbFile) throws SQLException {
    200                 // Load in all mail.
    201                 Connection c = DriverManager.getConnection("jdbc:sqlite:" + dbFile.toAbsolutePath().toString());
    202                 String sql = "SELECT * FROM EXPMAIL";
    203                 PreparedStatement query = c.prepareStatement(sql);
    204                 ResultSet allMail = query.executeQuery();
    205 
    206                 // Construct all mail objects using content from database.
    207                 while(allMail.next()) {
    208                         String timestamp = allMail.getString("time");
    209                         String from = allMail.getString("snd");
    210                         String to = allMail.getString("rec");
    211                         String msg = allMail.getString("msg");
    212                         String msg2 = allMail.getString("msg2");
    213                         String[] opts = allMail.getString("opts").split(",");
    214                         opts[0] = opts[0].replace("[", "");
    215                         opts[opts.length - 1] = opts[opts.length - 1].replace("]", "");
    216                         String[] optsVal = allMail.getString("optsval").split(",");
    217                         optsVal[0] = optsVal[0].replace("[", "");
    218                         optsVal[optsVal.length - 1] = optsVal[optsVal.length - 1].replace("]", "");
    219                        
    220                         Map<String, String> options = new HashMap<String, String>();
    221                         for (int i = 0, o = 0; i < opts.length && o < optsVal.length; i++, o++) {
    222                                 String key = opts[i].trim();
    223                                 String val = optsVal[o].trim();
    224                                 options.put(key, val);
    225                         }
    226                        
    227                         Mail.MailEntry mail = new Mail.MailEntry(timestamp, from, to, msg, msg2, options);
    228                         mail.deadDropSource = dbFile;
    229                         Mail.addEntry(mail);
    230                 }
    231                
    232                 // Disconnect from database.
    233                 allMail.close();
    234                 query.close();
    235                 c.close();
    236         }
    237        
    238         public final void loadMailDatabase() throws SQLException, FileNotFoundException, ParseException {
    239                 Path deadDropPath = Paths.get(FrameIO.DEAD_DROPS_PATH);
    240                 for (File connectionDir: deadDropPath.toFile().listFiles()) {
    241                         if (connectionDir.isDirectory()) {
    242                                 Path deaddropforcontactPath = Paths.get(connectionDir.getAbsolutePath());
    243                                 Path dbFile = deaddropforcontactPath.resolve(UserSettings.UserName.get() + ".db");
    244                                 if (dbFile.toFile().exists()) {
    245                                         loadMailFromFile(dbFile);
    246                                 }
    247                                 clearOldMailFromDatabase(deaddropforcontactPath);
    248                         }
    249                 }
    250         }
    251 
    252         public final void updateLastReadMailTime(Path deaddropforcontactPath) {
    253                 Path timestamp = deaddropforcontactPath.resolve(UserSettings.UserName.get() + ".last-accessed");
    254                 try(FileWriter out = new FileWriter(timestamp.toFile())) {
    255                         out.write(Formatter.getDateTime() + System.getProperty("line.separator"));
    256                 } catch (IOException e) {
    257                         e.printStackTrace();
    258                 }
    259         }
    260        
    261         private void clearOldMailFromDatabase(Path directory) throws FileNotFoundException, ParseException, SQLException {
    262                 File[] files = directory.toFile().listFiles(new FileFilter() {
    263                         @Override
    264                         public boolean accept(File file) {
    265                                 return !file.getName().startsWith(UserSettings.UserName.get());
    266                         }
    267                 });
    268                
    269                 File dbFile = null;
    270                 File lastAccessedFile = null;
    271                 for (File file: files) {
    272                         if (file.getName().endsWith(".db")) {
    273                                 dbFile = file;
    274                         } else {
    275                                 lastAccessedFile = file;
    276                         }
    277                 }
    278                
    279                 if (dbFile == null || lastAccessedFile == null) {
    280                         return; // Not the end of the world if we cannot clear out old messages, these files may not be present yet if the others are recently new.
    281                 }
    282                
    283                 SimpleDateFormat format = new SimpleDateFormat("ddMMMyyyy[HH:mm]");
    284                 Date timestamp = null;
    285                 try(Scanner in = new Scanner(lastAccessedFile)) {
    286                         timestamp = format.parse(in.nextLine());
    287                 } catch (ParseException e) {
    288                         return; // Not the end of the world if we cannot clear out old messages, the database might be empty.
    289                 }
    290                
    291                 Connection c = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
    292                 String sql = "SELECT * FROM EXPMAIL";
    293                 PreparedStatement query = c.prepareStatement(sql);
    294                 ResultSet allMail = query.executeQuery();
    295                 Set<String> oldTimestamps = new HashSet<String>();
    296                
    297                 while (allMail.next()) {
    298                         String time = allMail.getString("time");
    299                         Date messageTimestamp = format.parse(time);
    300                         if (timestamp.after(messageTimestamp)) {
    301                                 oldTimestamps.add(time);
    302                         }
    303                 }
    304                
    305                 if (oldTimestamps.isEmpty()) {
    306                         return;
    307                 }
    308                
    309                 for(String oldTimestamp: oldTimestamps) {
    310                         System.out.println("Deleting message with timestamp: " + oldTimestamp);
    311                         sql = "DELETE FROM EXPMAIL WHERE time='" + oldTimestamp + "'";
    312                         query = c.prepareStatement(sql);
    313                         query.executeUpdate();
    314                 }               
    315181        }
    316182         
Note: See TracChangeset for help on using the changeset viewer.