//Receives messages from the Mailbox. Note that the state parameter is ignored; we're already //carrying our state in the AsyncState property of the base class. However, Receive() has to //take a single parameter of type Object in order to be a valid WaitCallback delegate. private void doReceive( object state ) { Pop3 pop3 = null; bool bCaughtException = false; //This part does the work of connecting to the POP3 account, logging in, and //checking for new messages. If any messages were found, they will be downloaded //and stored in this.Messages try { Mailbox box = this.AsyncState as Mailbox; string server = box.Options.MailServer; string username = box.Address; string password = box.Options.MailServerPassword; pop3 = new Pop3( ); pop3.User = username; pop3.Password = password; pop3.Connect( server ); if ( pop3.HasTimeStamp ) pop3.APOPLogin( ); else pop3.Login( ); pop3.GetAccountStat( ); this.Messages = new SimpleMailMessage[ pop3.MessageCount ]; log.Debug(string.Format("pop3 check -- {0} - mail count:{1}", username, pop3.MessageCount)); //If we don't have any messages, go to sleep for a little while and try again. //We'll keep doing this sleep/retry loop until a message shows up. That way, SoapTransport //never has to pay any attention to us until we actually have work for it to do. if ( pop3.MessageCount == 0 ) { pop3.Close( ); pop3 = null; SleepAndRetry( box.Options.RetrySeconds ); return; } for ( int i = 1; i <= pop3.MessageCount; i++ ) { try { string message = pop3.GetMessage( i ); this.Messages[ i - 1 ] = SimpleMailMessage.Parse( message ); } finally { pop3.DeleteMessage( i ); } } } catch ( Exception e ) { //This part's very important. Since we're running on a ThreadPool thread right now, any exceptions //thrown on this thread will be swallowed by the ThreadPool. If an exception happens, we need to //somehow marshal it back to the thread that initiated the async operation and rethrow it there. //Forutnately, the AsyncResult base class lets us do that. We'll catch the exception here and //pass it to Complete(). When the originating thread calls AsyncResult.End() on us, the AsyncResult base //class will rethrow the exception on the right thread so it can be handled by the application. bCaughtException = true; base.Complete( false, e ); } finally { if ( pop3 != null ) pop3.Close( true ); } if ( !bCaughtException ) base.Complete( false ); }