Changeset 690


Ignore:
Timestamp:
08/21/10 15:05:48 (21 months ago)
Author:
octorian
Message:

Parse fetch responses synchronously with data download (#222)

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/imap/ImapProtocol.java

    r689 r690  
    476476        } 
    477477 
    478         byte[][] rawList = executeResponse(FETCH, 
     478        final Vector result = new Vector(lastIndex - firstIndex); 
     479         
     480        executeResponse(FETCH, 
    479481                Integer.toString(firstIndex) + CHAR_COLON + 
    480                 Integer.toString(lastIndex) + " (FLAGS UID)", progressHandler); 
    481  
    482         return prepareFetchFlagsResponse(rawList, progressHandler); 
     482                Integer.toString(lastIndex) + " (FLAGS UID)", 
     483                new ExecuteCallback() { public void processResponse(byte[] rawLine) { 
     484                    FetchFlagsResponse response = prepareFetchFlagsResponse(rawLine); 
     485                    if(response != null) { 
     486                        result.addElement(response); 
     487                    } 
     488                }}, 
     489                progressHandler); 
     490 
     491        FetchFlagsResponse[] resultArray = new FetchFlagsResponse[result.size()]; 
     492        result.copyInto(resultArray); 
     493        return resultArray; 
    483494    } 
    484495 
     
    497508        } 
    498509 
    499         byte[][] rawList = executeResponse(UID_FETCH, 
     510        final Vector result = new Vector(); 
     511         
     512        executeResponse(UID_FETCH, 
    500513                Integer.toString(uidNext) + CHAR_COLON_ASTERISK + 
    501                 " (FLAGS UID)", progressHandler); 
    502  
    503         return prepareFetchFlagsResponse(rawList, progressHandler); 
    504     } 
    505  
    506     private FetchFlagsResponse[] prepareFetchFlagsResponse(byte[][] rawList, 
    507         MailProgressHandler progressHandler) throws IOException, MailException { 
    508         if (progressHandler != null) { 
    509             progressHandler.mailProgress(MailProgressHandler.TYPE_PROCESSING, 
    510                 0, -1); 
    511         } 
    512  
    513         Vector flagResponses = new Vector(); 
    514  
    515         if (progressHandler != null) { 
    516             progressHandler.mailProgress( 
    517                     MailProgressHandler.TYPE_PROCESSING, 0, rawList.length); 
     514                " (FLAGS UID)", 
     515                new ExecuteCallback() { public void processResponse(byte[] rawLine) { 
     516                    FetchFlagsResponse response = prepareFetchFlagsResponse(rawLine); 
     517                    if(response != null) { 
     518                        result.addElement(response); 
     519                    } 
     520                }}, 
     521                progressHandler); 
     522 
     523        FetchFlagsResponse[] resultArray = new FetchFlagsResponse[result.size()]; 
     524        result.copyInto(resultArray); 
     525        return resultArray; 
     526    } 
     527 
     528    private FetchFlagsResponse prepareFetchFlagsResponse(byte[] rawText) { 
     529        if(rawText == null || rawText.length == 0 || rawText[0] != CHAR_ASTERISK) { 
     530            return null; 
    518531        } 
    519532         
    520         for (int i = 0; i < rawList.length; i++) { 
    521             byte[] rawText = rawList[i]; 
    522             if(rawText == null || rawText.length == 0 || rawText[0] != CHAR_ASTERISK) { 
    523                 continue; 
    524             } 
     533        FetchFlagsResponse flagRespItem = new FetchFlagsResponse(); 
     534         
     535        try { 
     536            Vector parsedText = null; 
     537 
     538            try { 
     539                int offset = Arrays.getIndex(rawText, (byte)'('); 
     540                parsedText = ImapParser.parenListParser(rawText, offset, rawText.length - offset); 
     541            } catch (Exception exp) { 
     542                parsedText = null; 
     543                return null; 
     544            } 
     545 
    525546             
    526             try { 
    527                 Vector parsedText = null; 
    528  
    529                 try { 
    530                     int offset = Arrays.getIndex(rawText, (byte)'('); 
    531                     parsedText = ImapParser.parenListParser(rawText, offset, rawText.length - offset); 
    532                 } catch (Exception exp) { 
    533                     parsedText = null; 
    534  
    535                     continue; 
    536                 } 
    537  
    538                 FetchFlagsResponse flagRespItem = new FetchFlagsResponse(); 
    539                 flagRespItem.flags = null; 
    540  
    541                 // Iterate through results, locating and parsing the 
    542                 // FLAGS and ENVELOPE sections in an order-independent way. 
    543                 int parsedSize = parsedText.size(); 
    544  
    545                 for (int j = 0; j < parsedSize; j++) { 
    546                     if (parsedText.elementAt(j) instanceof String) { 
    547                         if (((String) parsedText.elementAt(j)).equals(FLAGS) && 
    548                                 (parsedSize > (j + 1)) && 
    549                                 parsedText.elementAt(j + 1) instanceof Vector) { 
    550                             flagRespItem.flags = ImapParser.parseMessageFlags((Vector) parsedText.elementAt(j + 
     547            flagRespItem.flags = null; 
     548 
     549            // Iterate through results, locating and parsing the 
     550            // FLAGS and ENVELOPE sections in an order-independent way. 
     551            int parsedSize = parsedText.size(); 
     552 
     553            for (int j = 0; j < parsedSize; j++) { 
     554                if (parsedText.elementAt(j) instanceof String) { 
     555                    if (((String) parsedText.elementAt(j)).equals(FLAGS) && 
     556                            (parsedSize > (j + 1)) && 
     557                            parsedText.elementAt(j + 1) instanceof Vector) { 
     558                        flagRespItem.flags = ImapParser.parseMessageFlags((Vector) parsedText.elementAt(j + 
     559                                    1)); 
     560                    } else if (((String) parsedText.elementAt(j)).equals( 
     561                                UID) && (parsedSize > (j + 1)) && 
     562                            parsedText.elementAt(j + 1) instanceof String) { 
     563                        try { 
     564                            flagRespItem.uid = Integer.parseInt((String) parsedText.elementAt(j + 
    551565                                        1)); 
    552                         } else if (((String) parsedText.elementAt(j)).equals( 
    553                                     UID) && (parsedSize > (j + 1)) && 
    554                                 parsedText.elementAt(j + 1) instanceof String) { 
    555                             try { 
    556                                 flagRespItem.uid = Integer.parseInt((String) parsedText.elementAt(j + 
    557                                             1)); 
    558                             } catch (NumberFormatException e) { 
    559                                 flagRespItem.uid = -1; 
    560                             } 
     566                        } catch (NumberFormatException e) { 
     567                            flagRespItem.uid = -1; 
    561568                        } 
    562569                    } 
    563570                } 
    564  
    565                 if (flagRespItem.flags == null) { 
    566                     flagRespItem.flags = new MessageFlags(); 
    567                 } 
    568  
    569                 // Find the message index in the reply 
    570                 int spaceIndex = Arrays.getIndex(rawText, (byte)' '); 
    571                 int fetchIndex = StringArrays.indexOf(rawText, FETCH.getBytes(), spaceIndex); 
    572                 int midx = StringArrays.parseInt(rawText, spaceIndex + 1, fetchIndex - spaceIndex - 2); 
    573  
    574                 flagRespItem.index = midx; 
    575                 flagResponses.addElement(flagRespItem); 
    576             } catch (Exception exp) { 
    577                 EventLogger.logEvent(AppInfo.GUID, 
    578                     ("Parse error: " + exp).getBytes(), EventLogger.ERROR); 
    579             } 
    580  
    581             if (progressHandler != null) { 
    582                 progressHandler.mailProgress( 
    583                         MailProgressHandler.TYPE_PROCESSING, i, rawList.length); 
    584             } 
    585         } 
    586  
    587         FetchFlagsResponse[] result = new FetchFlagsResponse[flagResponses.size()]; 
    588         flagResponses.copyInto(result); 
    589  
    590         if (progressHandler != null) { 
    591             progressHandler.mailProgress( 
    592                     MailProgressHandler.TYPE_PROCESSING, 
    593                     rawList.length, rawList.length); 
    594         } 
    595  
    596         return result; 
     571            } 
     572 
     573            if (flagRespItem.flags == null) { 
     574                flagRespItem.flags = new MessageFlags(); 
     575            } 
     576 
     577            // Find the message index in the reply 
     578            int spaceIndex = Arrays.getIndex(rawText, (byte)' '); 
     579            int fetchIndex = StringArrays.indexOf(rawText, FETCH.getBytes(), spaceIndex); 
     580            int midx = StringArrays.parseInt(rawText, spaceIndex + 1, fetchIndex - spaceIndex - 2); 
     581 
     582            flagRespItem.index = midx; 
     583        } catch (Throwable exp) { 
     584            EventLogger.logEvent(AppInfo.GUID, 
     585                ("Parse error: " + exp).getBytes(), EventLogger.ERROR); 
     586            flagRespItem = null; 
     587        } 
     588 
     589        return flagRespItem; 
    597590    } 
    598591 
     
    605598     */ 
    606599    public void executeFetchEnvelope(int firstIndex, int lastIndex, 
    607         FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
     600        final FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
    608601        throws IOException, MailException { 
    609602        if (EventLogger.getMinimumLevel() >= EventLogger.DEBUG_INFO) { 
     
    613606        } 
    614607 
    615         byte[][] rawList = executeResponse(FETCH, 
     608        executeResponse(FETCH, 
    616609                Integer.toString(firstIndex) + CHAR_COLON + 
    617610                Integer.toString(lastIndex) + 
    618                 " (FLAGS UID ENVELOPE BODYSTRUCTURE)", progressHandler); 
    619  
    620         prepareFetchEnvelopeResponse(rawList, callback, progressHandler); 
     611                " (FLAGS UID ENVELOPE BODYSTRUCTURE)", 
     612                new ExecuteCallback() { public void processResponse(byte[] rawLine) { 
     613                    prepareFetchEnvelopeResponse(rawLine, callback); 
     614                }}, 
     615                progressHandler); 
    621616    } 
    622617 
     
    628623     */ 
    629624    public void executeFetchEnvelopeUid(int uidNext, 
    630         FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
     625        final FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
    631626        throws IOException, MailException { 
    632627        if (EventLogger.getMinimumLevel() >= EventLogger.DEBUG_INFO) { 
     
    636631        } 
    637632 
    638         byte[][] rawList = executeResponse(UID_FETCH, 
     633        executeResponse(UID_FETCH, 
    639634                Integer.toString(uidNext) + CHAR_COLON_ASTERISK + 
    640                 " (FLAGS UID ENVELOPE BODYSTRUCTURE)", progressHandler); 
    641  
    642         prepareFetchEnvelopeResponse(rawList, callback, progressHandler); 
     635                " (FLAGS UID ENVELOPE BODYSTRUCTURE)", 
     636                new ExecuteCallback() { public void processResponse(byte[] rawLine) { 
     637                    prepareFetchEnvelopeResponse(rawLine, callback); 
     638                }}, 
     639                progressHandler); 
    643640    } 
    644641 
     
    650647     */ 
    651648    public void executeFetchEnvelopeUid(int[] uids, 
    652         FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
     649        final FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
    653650        throws IOException, MailException { 
    654651        if (uids.length == 0) { 
     
    675672        } 
    676673 
    677         byte[][] rawList = executeResponse(UID_FETCH, 
    678                 uidList + " (FLAGS UID ENVELOPE BODYSTRUCTURE)", progressHandler); 
    679  
    680         prepareFetchEnvelopeResponse(rawList, callback, progressHandler); 
    681     } 
    682  
    683     private void prepareFetchEnvelopeResponse(byte[][] rawList, 
    684         FetchEnvelopeCallback callback, MailProgressHandler progressHandler) 
    685         throws IOException, MailException { 
    686         if (progressHandler != null) { 
    687             progressHandler.mailProgress(MailProgressHandler.TYPE_PROCESSING, 
    688                 0, -1); 
    689         } 
    690  
    691         if (progressHandler != null) { 
    692             progressHandler.mailProgress( 
    693                     MailProgressHandler.TYPE_PROCESSING, 0, rawList.length); 
    694         } 
    695  
    696         for (int i = 0; i < rawList.length; i++) { 
    697             byte[] rawText = rawList[i]; 
    698             if(rawText == null || rawText.length == 0 || rawText[0] != CHAR_ASTERISK) { 
    699                 continue; 
    700             } 
    701              
    702             FetchEnvelopeResponse envRespItem = null; 
     674        executeResponse(UID_FETCH, 
     675                uidList + " (FLAGS UID ENVELOPE BODYSTRUCTURE)", 
     676                new ExecuteCallback() { public void processResponse(byte[] rawLine) { 
     677                    prepareFetchEnvelopeResponse(rawLine, callback); 
     678                }}, 
     679                progressHandler); 
     680    } 
     681 
     682    private void prepareFetchEnvelopeResponse(byte[] rawText, FetchEnvelopeCallback callback) { 
     683        if(rawText == null || rawText.length == 0 || rawText[0] != CHAR_ASTERISK) { 
     684            return; 
     685        } 
     686         
     687        FetchEnvelopeResponse envRespItem = null; 
     688        try { 
     689            MessageEnvelope env = null; 
     690            ImapParser.MessageSection structure = null; 
     691            Vector parsedText = null; 
     692 
    703693            try { 
    704                 MessageEnvelope env = null; 
    705                 ImapParser.MessageSection structure = null; 
    706                 Vector parsedText = null; 
    707  
    708                 try { 
    709                     int offset = Arrays.getIndex(rawText, (byte)'('); 
    710                     parsedText = ImapParser.parenListParser(rawText, offset, rawText.length - offset); 
    711                 } catch (Exception exp) { 
    712                     continue; 
    713                 } 
    714  
    715                 envRespItem = new FetchEnvelopeResponse(); 
    716                 envRespItem.flags = null; 
    717  
    718                 // Iterate through results, locating and parsing the 
    719                 // FLAGS and ENVELOPE sections in an order-independent way. 
    720                 int parsedSize = parsedText.size(); 
    721  
    722                 for (int j = 0; j < parsedSize; j++) { 
    723                     if (FLAGS.equals(parsedText.elementAt(j)) 
    724                             && (parsedSize > (j + 1)) 
    725                             && parsedText.elementAt(j + 1) instanceof Vector) { 
    726                         envRespItem.flags = ImapParser.parseMessageFlags((Vector) parsedText.elementAt(j + 1)); 
    727                     } 
    728                     else if (UID.equals(parsedText.elementAt(j)) 
    729                             && (parsedSize > (j + 1)) 
    730                             && parsedText.elementAt(j + 1) instanceof String) { 
    731                         try { 
    732                             envRespItem.uid = Integer.parseInt((String) parsedText.elementAt(j + 1)); 
    733                         } catch (NumberFormatException e) { 
    734                             envRespItem.uid = -1; 
    735                         } 
    736                     } 
    737                     else if (ENVELOPE.equals(parsedText.elementAt(j)) 
    738                             && (parsedSize > (j + 1)) 
    739                             && parsedText.elementAt(j + 1) instanceof Vector) { 
    740                         env = ImapParser.parseMessageEnvelope((Vector) parsedText.elementAt(j + 1)); 
    741                     } 
    742                     else if (BODYSTRUCTURE.equals(parsedText.elementAt(j)) 
    743                             && (parsedSize > (j + 1)) 
    744                             && parsedText.elementAt(j + 1) instanceof Vector) { 
    745                         structure = ImapParser.parseMessageStructureParameter((Vector) parsedText.elementAt(j + 1)); 
    746                     } 
    747                 } 
    748  
    749                 // If either of the above sections were not found, then populate 
    750                 // the reply with the relevant dummy data. 
    751                 if (env == null) { 
    752                     env = ImapParser.generateDummyEnvelope(); 
    753                 } 
    754  
    755                 if (envRespItem.flags == null) { 
    756                     envRespItem.flags = new MessageFlags(); 
    757                 } 
    758  
    759                 // Find the message index in the reply 
    760                 int spaceIndex = Arrays.getIndex(rawText, (byte)' '); 
    761                 int fetchIndex = StringArrays.indexOf(rawText, FETCH.getBytes(), spaceIndex); 
    762                 int midx = StringArrays.parseInt(rawText, spaceIndex + 1, fetchIndex - spaceIndex - 2); 
    763  
    764                 envRespItem.index = midx; 
    765                 envRespItem.envelope = env; 
    766                 envRespItem.structure = structure; 
     694                int offset = Arrays.getIndex(rawText, (byte)'('); 
     695                parsedText = ImapParser.parenListParser(rawText, offset, rawText.length - offset); 
    767696            } catch (Exception exp) { 
    768                 EventLogger.logEvent(AppInfo.GUID, 
    769                     ("Parse error: " + exp).getBytes(), EventLogger.ERROR); 
    770                 envRespItem = null; 
    771             } 
    772  
    773             if (envRespItem != null) { 
    774                 callback.responseAvailable(envRespItem); 
    775             } 
    776  
    777             if (progressHandler != null) { 
    778                 progressHandler.mailProgress( 
    779                         MailProgressHandler.TYPE_PROCESSING, i, rawList.length); 
    780             } 
    781         } 
    782  
    783         callback.responseAvailable(null); 
     697                return; 
     698            } 
     699 
     700            envRespItem = new FetchEnvelopeResponse(); 
     701            envRespItem.flags = null; 
     702 
     703            // Iterate through results, locating and parsing the 
     704            // FLAGS and ENVELOPE sections in an order-independent way. 
     705            int parsedSize = parsedText.size(); 
     706 
     707            for (int j = 0; j < parsedSize; j++) { 
     708                if (FLAGS.equals(parsedText.elementAt(j)) 
     709                        && (parsedSize > (j + 1)) 
     710                        && parsedText.elementAt(j + 1) instanceof Vector) { 
     711                    envRespItem.flags = ImapParser.parseMessageFlags((Vector) parsedText.elementAt(j + 1)); 
     712                } 
     713                else if (UID.equals(parsedText.elementAt(j)) 
     714                        && (parsedSize > (j + 1)) 
     715                        && parsedText.elementAt(j + 1) instanceof String) { 
     716                    try { 
     717                        envRespItem.uid = Integer.parseInt((String) parsedText.elementAt(j + 1)); 
     718                    } catch (NumberFormatException e) { 
     719                        envRespItem.uid = -1; 
     720                    } 
     721                } 
     722                else if (ENVELOPE.equals(parsedText.elementAt(j)) 
     723                        && (parsedSize > (j + 1)) 
     724                        && parsedText.elementAt(j + 1) instanceof Vector) { 
     725                    env = ImapParser.parseMessageEnvelope((Vector) parsedText.elementAt(j + 1)); 
     726                } 
     727                else if (BODYSTRUCTURE.equals(parsedText.elementAt(j)) 
     728                        && (parsedSize > (j + 1)) 
     729                        && parsedText.elementAt(j + 1) instanceof Vector) { 
     730                    structure = ImapParser.parseMessageStructureParameter((Vector) parsedText.elementAt(j + 1)); 
     731                } 
     732            } 
     733 
     734            // If either of the above sections were not found, then populate 
     735            // the reply with the relevant dummy data. 
     736            if (env == null) { 
     737                env = ImapParser.generateDummyEnvelope(); 
     738            } 
     739 
     740            if (envRespItem.flags == null) { 
     741                envRespItem.flags = new MessageFlags(); 
     742            } 
     743 
     744            // Find the message index in the reply 
     745            int spaceIndex = Arrays.getIndex(rawText, (byte)' '); 
     746            int fetchIndex = StringArrays.indexOf(rawText, FETCH.getBytes(), spaceIndex); 
     747            int midx = StringArrays.parseInt(rawText, spaceIndex + 1, fetchIndex - spaceIndex - 2); 
     748 
     749            envRespItem.index = midx; 
     750            envRespItem.envelope = env; 
     751            envRespItem.structure = structure; 
     752        } catch (Exception exp) { 
     753            EventLogger.logEvent(AppInfo.GUID, 
     754                ("Parse error: " + exp).getBytes(), EventLogger.ERROR); 
     755            envRespItem = null; 
     756        } 
     757 
     758        if (envRespItem != null) { 
     759            callback.responseAvailable(envRespItem); 
     760        } 
    784761    } 
    785762 
     
    13931370    } 
    13941371 
     1372    /** 
     1373     * Executes an IMAP command, invoking the supplied callback on each line 
     1374     * of the response. 
     1375     *  
     1376     * @param command IMAP command 
     1377     * @param arguments Arguments for the command 
     1378     * @param callback the callback to invoke on each line of the response 
     1379     * @param progressHandler the progress handler 
     1380     * @return List of returned strings 
     1381     */ 
     1382    protected void executeResponse(String command, String arguments, 
     1383            ExecuteCallback callback, MailProgressHandler progressHandler) 
     1384    throws IOException, MailException { 
     1385         
     1386        String tag = TAG_PREFIX + commandCount++ + CHAR_SP; 
     1387        connection.sendCommand(tag + command + 
     1388            ((arguments == null) ? "" : (CHAR_SP + arguments))); 
     1389 
     1390        byte[] tagBytes = tag.getBytes(); 
     1391 
     1392        int preCount = connection.getBytesReceived(); 
     1393        byte[] temp = connection.receive(executeResponseTester); 
     1394        int postCount = connection.getBytesReceived(); 
     1395 
     1396        if (progressHandler != null) { 
     1397            progressHandler.mailProgress(MailProgressHandler.TYPE_NETWORK, 
     1398                (postCount - preCount), -1); 
     1399        } 
     1400 
     1401        while (!StringArrays.startsWith(temp, tagBytes)) { 
     1402            try { 
     1403                callback.processResponse(temp); 
     1404            } catch (Throwable t) { 
     1405                EventLogger.logEvent(AppInfo.GUID, 
     1406                        ("Unable to parse response: " + t.getMessage()).getBytes(), 
     1407                        EventLogger.ERROR); 
     1408            } 
     1409             
     1410            preCount = postCount; 
     1411            temp = connection.receive(executeResponseTester); 
     1412            postCount = connection.getBytesReceived(); 
     1413 
     1414            if (progressHandler != null) { 
     1415                progressHandler.mailProgress(MailProgressHandler.TYPE_NETWORK, 
     1416                    (postCount - preCount), -1); 
     1417            } 
     1418        } 
     1419 
     1420        if (StringArrays.startsWith(temp, BAD_PREFIX, tagBytes.length) || 
     1421                StringArrays.startsWith(temp, NO_PREFIX, 
     1422                    tagBytes.length)) { 
     1423            throw new MailException(new String(temp)); 
     1424        } 
     1425    } 
     1426     
     1427    /** 
     1428     * Callback interface for <code>executeResponse()</code>. 
     1429     */ 
     1430    protected interface ExecuteCallback { 
     1431        void processResponse(byte[] rawLine); 
     1432    } 
     1433     
    13951434    /** 
    13961435     * Executes an IMAP command, and returns the reply as an 
  • trunk/LogicMailTests/src/org/logicprobe/LogicMail/mail/imap/ImapProtocolTest.java

    r689 r690  
    10941094        } 
    10951095         
     1096        protected void executeResponse(String command, String arguments, 
     1097                ExecuteCallback callback, MailProgressHandler progressHandler) 
     1098                throws IOException, MailException { 
     1099            assertTrue("No expectations", !executeExpectations.isEmpty()); 
     1100 
     1101            ExecuteExpectation expect = (ExecuteExpectation) executeExpectations.lastElement(); 
     1102            assertEquals("Bad command", expect.command, command); 
     1103            assertEquals("Bad arguments", expect.arguments, arguments); 
     1104            executeExpectations.removeElement(expect); 
     1105 
     1106            for(int i=0; i<expect.result.length; i++) { 
     1107                callback.processResponse(expect.result[i].getBytes()); 
     1108            } 
     1109        } 
     1110         
    10961111        private class ExecuteExpectation { 
    10971112            public String command; 
Note: See TracChangeset for help on using the changeset viewer.