void TestWriteEmail(int numAttachments)
{
	Email email;
	InitEmail(email);
	
	MojRefCountedPtr<AsyncEmailWriter> writer( new AsyncEmailWriter(email) );
	
	// Create a body part
	EmailPartList partList;
	partList.push_back( CreateBodyPart("test1") );
	
	// Create some attachments
	for(int i = 0; i < numAttachments; i++) {
		std::stringstream name;
		name << "attach" << i;
		
		EmailPartPtr attachmentPart( new EmailPart(EmailPart::ATTACHMENT) );
		attachmentPart->SetLocalFilePath(name.str());
		partList.push_back(attachmentPart);
	}
	writer->SetPartList(partList);
	
	// Set up a fake file "test1" in our mock factory
	boost::shared_ptr<MockAsyncIOChannelFactory> ioFactory( new MockAsyncIOChannelFactory() );
	writer->SetAsyncIOChannelFactory(ioFactory);
	ioFactory->SetFileData("test1", "Email body");
	
	// Make some fake attachments
	for(int i = 0; i < numAttachments; i++) {
		std::stringstream name, data;
		name << "attach" << i;
		data << "Attachment data " << i;
		ioFactory->SetFileData(name.str().c_str(), data.str());
	}
	
	std::string output;
	WriteEmail(writer, output);
	
	//fprintf(stderr, "Email:\n%s\n", output.c_str());
}
MojErr SmtpSendMailCommand::FinishCalculateEmailSize(const std::exception* exc)
{
	if(exc) {
		HandleException(*exc, __func__, __FILE__, __LINE__);
		return MojErrNone;
	}
	
	try {
		m_bytesLeft = m_counter->GetBytesWritten();
		MojLogInfo(m_log, "done calculating email size");
		MojLogDebug(m_log, "email size: %d bytes", m_bytesLeft);

		m_write_state = State_SendMailFrom;

		// If SIZE extension is present, and server specified a fixed maximum size,
		// check calculated mail size against server limit.
		if (m_session.GetSizeMax() && m_session.GetSizeMaxValue() > 0) {
			if (m_bytesLeft > m_session.GetSizeMaxValue()) {
				MojLogInfo(m_log, "Outgoing mail is larger than server stated SIZE, so rejecting immediately");
				m_error.internalError = "Message larger than server stated limit, not trying to send";
				m_error.errorCode = MailError::EMAIL_SIZE_EXCEEDED;
				m_error.errorText = ""; // No server text, cannot present message
				m_error.errorOnEmail = true;
				m_write_state = State_SendErrorRset;
			}
		}

		WriteEmail();
		
	} catch(const std::exception& e) {
		HandleException(e, __func__, __FILE__, __LINE__);
	} catch(...) {
		HandleUnknownException();
	}
	
	return MojErrNone;
}
MojErr SmtpSendMailCommand::HandleResponse(const std::string& line)
{
	try {
		switch (m_write_state) {
		case State_SendMailFrom:
		{
			MojLogInfo(m_log, "MAIL FROM command response");

			if (m_status == Status_Ok) {
				MojLogInfo(m_log, "MAIL FROM command +OK");
				m_toIdx = 0;
				if(m_toIdx < m_toAddress.size()) {
					m_write_state = State_SendRcptTo;
				} else {
					m_error.errorCode = MailError::BAD_RECIPIENTS; // Error out if for some reason there is no recipient.
					m_error.errorOnEmail = true;
					m_error.errorOnAccount = false;
					m_error.internalError = "Error setting forward address";
					m_write_state = State_SendErrorRset;
				}
				WriteEmail();
			} else {
				MojLogInfo(m_log, "MAIL FROM command -ERR");
				m_error = GetStandardError();
				m_error.internalError = "Error setting reverse address";
				m_write_state = State_SendErrorRset;
				WriteEmail();
			}
			break;
		}
		case State_SendRcptTo:
		{
			MojLogInfo(m_log, "RCPT TO command response");
 
			if (m_status == Status_Ok) {
				m_toIdx++;
				if (m_toIdx < m_toAddress.size()) {
					MojLogInfo(m_log, "RCPT TO command +OK, more to come");
					m_write_state = State_SendRcptTo;
				} else {
					MojLogInfo(m_log, "RCPT TO command +OK, done");
					m_write_state = State_SendData;
				}
				WriteEmail();
			
			} else {
				MojLogInfo(m_log, "RCPT TO command -ERR");
				m_error =  GetStandardError();
				if (m_status == 550) { // general failure means bad recipient
					m_error.errorCode = MailError::BAD_RECIPIENTS;
					m_error.errorOnEmail = true;
					m_error.errorOnAccount = false;
				}
				// 452 is technically a non-fatal error that says no more recipients can be
				// added, on the expectation we'll go and send our mail, and then send a
				// copy to the next batch of recipients. Instead, we'll treat this as a 
				// permanent error, and not send it to anyone (by sending RSET, and not DATA).
				// 552 is (as the spec says) an old and occasionally seen typo of 452.
				if (m_status == 452 || m_status == 552) {
					m_error.errorCode = MailError::BAD_RECIPIENTS; // too many, actually
					m_error.errorOnEmail = true;
					m_error.errorOnAccount = false;
				}
				m_error.internalError = "Error setting forward address";
				m_write_state = State_SendErrorRset;
				WriteEmail();
			}
			break;
		}
		case State_SendData:
		{
			MojLogInfo(m_log, "DATA command response");

			if (m_status == Status_Ok) {
				MojLogInfo(m_log, "DATA command +OK");
				m_write_state = State_SendBody;
				WriteEmail();
			
			} else {
				MojLogInfo(m_log, "DATA command -ERR");
				m_error = GetStandardError();
				m_error.internalError = "Error starting mail body";
				m_write_state = State_SendErrorRset;
				WriteEmail();
			}
			break;
		}
		case State_SendBody:
		{
			MojLogInfo(m_log, "BODY command response");

			if (m_status == Status_Ok) {
				MojLogInfo(m_log, "BODY command +OK");
				m_write_state = State_SendRset;
				WriteEmail();
			
			} else {
				MojLogInfo(m_log, "BODY command -ERR");
				m_error = GetStandardError();
				m_error.internalError = "Error completing send";
				m_write_state = State_SendErrorRset;
				WriteEmail();
			}
			break;
		}
		case State_SendRset:
		{
			MojLogInfo(m_log, "RSET command response");

			if (m_status == Status_Ok) {
				MojLogInfo(m_log, "RSET command +OK");
				SendDone();
			} else {
				MojLogInfo(m_log, "RSET command -ERR");
				m_error = GetStandardError();
				m_error.internalError = "Error resetting";
				HandleSmtpError(m_error);
			}
			break;
		}
		case State_SendErrorRset:
		{
			// Handle an error response after clearing an error: if we had one bad e-mail, we want to
			// be sure we are in a good state before going to the next e-mail.
			HandleSmtpError(m_error);
			break;
		}
		default:
		{
			MojLogInfo(m_log, "Unknown write mail state %d in SmtpSendMailCommand::HandleResponse", m_write_state);
			HandleFailure("bad HandleResponse state");
			break;
		}
		}

	} catch(const std::exception& e) {
		HandleException(e, __func__, __FILE__, __LINE__);
	} catch(...) {
		HandleUnknownException();
	}
	
	return MojErrNone;
}
Example #4
0
int main ( int argc, char *argv[] )
{
    gettextinfo ( &StartupTextInfo );
    atexit ( exitcode );

    extern bool sound_flag;
    sound_flag = true;

    printf (
        "\n"
        "MailChess v %s by Don Cross <*****@*****.**>, 1 March 1996.\n"
        "http://www.intersrv.com/~dcross\n"
        "\n",
        MailChess_Version );

    const char * const help =
        "Use:  MAILCHES mailfile\n"
        "\n"
        "This program helps two people play chess by e-mail.  MailChess reads\n"
        "and writes a text file which can be sent back and forth by email.\n"
        "MailChess ignores e-mail headers and other extraneous text.\n"
        "\n"
        "If 'mailfile' exists, it is scanned for chess data and MailChess tries\n"
        "to restore a game in progress so that the next move can be made.\n"
        "\n"
        "If 'mailfile' does not exist, MailChess assumes that you want to\n"
        "start a new game, and that you will play White.\n"
        "In this case, you will make your first move and MailChess will\n"
        "create the file 'mailfile'.\n";

//  "If the optional parameter 'listfile' is specified, MailChess will\n"
//  "read the game encoded in 'mailfile' and create a human-readable\n"
//  "listing of the game in 'listfile', then immediately exit.\n";

    if ( argc != 2 && argc != 3 )
    {
        printf ( "%s", help );
        return 1;
    }

    ChessBoard theBoard;

    if ( argc == 3 )
    {
        if ( !ReadEmail ( 0, theBoard, argv[1] ) )
        {
            fprintf ( stderr, "No valid chess data in file '%s'\n", argv[1] );
            return 1;
        }

        FILE *out = fopen ( argv[2], "wt" );
        if ( !out )
        {
            fprintf ( stderr, "Cannot open file '%s' for write!\n", argv[2] );
            return 1;
        }

        ListChessGame ( theBoard, out );

        fclose ( out );
        printf ( "Game listing written to file '%s'\n", argv[2] );
        return 0;
    }

    ChessUI_dos_cga theUserInterface;

    ChessPlayer *player = new HumanChessPlayer ( theUserInterface );
    if ( !player )
    {
        fprintf ( stderr, "Error:  Not enough memory to run this program!\n" );
        return 1;
    }

    if ( !ReadEmail ( &theUserInterface, theBoard, argv[1] ) )
    {
        fprintf ( stderr, "The file '%s' does not exist.\n", argv[1] );
        fprintf ( stderr, "Do you want to start a new game and create '%s'?\n", argv[1] );
        fprintf ( stderr, "(y/n):  " );
        fflush ( stderr );
        char answer [20];
        answer[0] = '\0';
        fgets ( answer, sizeof(answer), stdin );
        if ( answer[0]!='y' && answer[0]!='Y' )
        {
            delete player;
            return 1;
        }
    }

    MoveList legalMoveList;
    ChessSide winner = SIDE_NEITHER;
    if ( theBoard.WhiteToMove() )
    {
        theBoard.GenWhiteMoves ( legalMoveList );
        if ( legalMoveList.num == 0 )
        {
            winner = theBoard.WhiteInCheck() ? SIDE_BLACK : SIDE_NEITHER;
        }
    }
    else
    {
        theBoard.GenBlackMoves ( legalMoveList );
        if ( legalMoveList.num == 0 )
        {
            winner = theBoard.BlackInCheck() ? SIDE_WHITE : SIDE_NEITHER;
        }
    }

    bool gameIsOver = (legalMoveList.num == 0);
    if ( !gameIsOver )
    {
        // Look for definite draws...

        if ( theBoard.IsDefiniteDraw(3) )
        {
            winner = SIDE_NEITHER;
            gameIsOver = true;
        }
    }

    // Now, 'gameIsOver' definitely has the correct value.

    if ( gameIsOver )
    {
        // Display the ending state of the game and let the
        // user gloat/sulk/sigh.

        HelpUser_EndOfGame ( winner );
        while ( (bioskey(0) & 0xff) != 0x1b );
        sprintf ( ExitMessage,
                  "This game is over.  MailChess has not changed '%s'.\n",
                  argv[1] );
    }
    else
    {
        // Read a single move from the user.
        // Ask the user if he/she is sure afterward.
        // If not, cancel the move and let them do another.
        // Otherwise, commit to the move, write the updated game
        // state to the text file, and exit.

        HelpUser_MakeMove();

        for(;;)
        {
            Move move;
            INT32 timeSpent = 0;

            bool moveWasRead = player->GetMove (
                                   theBoard,
                                   move,
                                   timeSpent );

            if ( moveWasRead )
            {
                theUserInterface.RecordMove ( theBoard, move, timeSpent );
                UnmoveInfo unmove;
                theBoard.MakeMove ( move, unmove );
                theUserInterface.DrawBoard ( theBoard );

                int promptY = theBoard.WhiteToMove() ? 25 : 24;

                gotoxy ( 20, promptY );
                printf ( "Are you sure this is the move you want to make? (Y/N) " );
                unsigned key = 0;
                while ( toupper(key) != 'Y' && toupper(key) != 'N' )
                {
                    key = bioskey(0) & 0xff;
                }

                if ( key == 'Y' || key == 'y' )
                {
                    WriteEmail ( theBoard, argv[1] );
                    sprintf ( ExitMessage, "Your move has been added to the file '%s'.\n", argv[1] );
                    break;
                }
                else
                {
                    gotoxy ( 1, promptY );
                    printf ( "                                                                          " );
                    theBoard.UnmakeMove ( move, unmove );
                    theUserInterface.DrawBoard ( theBoard );
                }
            }
            else
            {
                sprintf ( ExitMessage, "The file '%s' has not been changed.\n", argv[1] );
                break;
            }
        }
    }

    delete player;

    return 0;
}