/********************************************************************* * * Simple Mail Transfer Protocol (SMTP) Client * Module for Microchip TCP/IP Stack * -Provides ability to send Emails * -Reference: RFC 2821 * ********************************************************************* * FileName: SMTP.c * Dependencies: TCP, ARP, DNS, Tick * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32MX * Compiler: Microchip C32 v1.00 or higher * Microchip C30 v3.01 or higher * Microchip C18 v3.13 or higher * HI-TECH PICC-18 STD 9.50PL3 or higher * Company: Microchip Technology, Inc. * * Software License Agreement * * Copyright © 2002-2007 Microchip Technology Inc. All rights * reserved. * * Microchip licenses to you the right to use, modify, copy, and * distribute: * (i) the Software when embedded on a Microchip microcontroller or * digital signal controller product (“Device”) which is * integrated into Licensee’s product; or * (ii) ONLY the Software driver source files ENC28J60.c and * ENC28J60.h ported to a non-Microchip device used in * conjunction with a Microchip ethernet controller for the * sole purpose of interfacing with the ethernet controller. * * You should refer to the license agreement accompanying this * Software for additional information regarding your rights and * obligations. * * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE. * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Howard Schlunder 3/03/06 Original * Howard Schlunder 11/2/06 Vastly improved for release * ********************************************************************/ #define __SMTP_C #include "net/include/TCP.h" #if defined(STACK_USE_SMTP_CLIENT) #include "net/include/SMTP.h" #include "net/include/DNS.h" #include "net/include/tick.h" #include "net/include/arp.h" #include "net/include/helpers.h" #include "mpfs/include/mpfs.h" #include "eeprom/include/xeeprom.h" #if defined(SMTP_DEBUG) #include "uart/include/uart.h" extern void IPAddressToString(IP_ADDR *IPVal, char *str); #endif #define SMTP_USER "LOGIN" #define SMTP_PASSWORD "PASSWORD" #define SMTP_FROM "NAME@TEST.COM" #define SMS_FREE_FROM "test" #define SMTP_SERVER_REPLY_TIMEOUT (TICK_SECOND*8) #define SMTP_VAR_ESC_CHAR '%' // Public variables // Public string pointers controlling the mail message. // Application must set these after calling SMTPBeginUsage(). // Unneeded fields should be set to NULL. SMTP_POINTERS SMTPClient; // Internal variables static NODE_INFO SMTPServer; static TCP_SOCKET MySocket = INVALID_SOCKET; static enum _TransportState { TRANSPORT_HOME = 0, TRANSPORT_BEGIN, TRANSPORT_NAME_RESOLVE, TRANSPORT_NAME_RESOLVE_ARP, TRANSPORT_OBTAIN_SOCKET, TRANSPORT_SOCKET_OBTAINED, TRANSPORT_CLOSE, TRANSPORT_ERROR } TransportState = TRANSPORT_HOME; static enum _SMTPState { SMTP_HOME = 0, SMTP_HELO, SMTP_HELO_ACK, SMTP_AUTH_LOGIN, SMTP_AUTH_LOGIN_ACK, SMTP_AUTH_USERNAME, SMTP_AUTH_USERNAME_ACK, SMTP_AUTH_PASSWORD, SMTP_AUTH_PASSWORD_ACK, SMTP_MAILFROM, SMTP_MAILFROM_ACK, SMTP_RCPTTO_INIT, SMTP_RCPTTO, SMTP_RCPTTO_ACK, SMTP_RCPTTO_ISDONE, SMTP_RCPTTOCC_INIT, SMTP_RCPTTOCC, SMTP_RCPTTOCC_ACK, SMTP_RCPTTOCC_ISDONE, SMTP_RCPTTOBCC_INIT, SMTP_RCPTTOBCC, SMTP_RCPTTOBCC_ACK, SMTP_RCPTTOBCC_ISDONE, SMTP_DATA, SMTP_DATA_ACK, SMTP_DATA_HEADER, SMTP_DATA_BODY_INIT, SMTP_DATA_BODY, SMTP_DATA_BODY_END, SMTP_DATA_BODY_ACK, SMTP_QUIT_INIT, SMTP_QUIT } SMTPState; static enum _PutHeadersState { PUTHEADERS_FROM_INIT = 0, PUTHEADERS_FROM, PUTHEADERS_TO_INIT, PUTHEADERS_TO, PUTHEADERS_CC_INIT, PUTHEADERS_CC, PUTHEADERS_SUBJECT_INIT, PUTHEADERS_SUBJECT, PUTHEADERS_OTHER_INIT, PUTHEADERS_OTHER, PUTHEADERS_DONE } PutHeadersState; static enum _RXParserState { RX_BYTE_0 = 0, RX_BYTE_1, RX_BYTE_2, RX_BYTE_3, RX_SEEK_CR, RX_SEEK_LF } RXParserState; static union _SMTPFlags { BYTE Val; struct { unsigned char RXSkipResponse:1; // LSB unsigned char SMTPInUse:1; // invio in corso unsigned char SentSuccessfully:1; // invio OK unsigned char ReadyToStart:1; // pronto a ripartire unsigned char ReadyToFinish:1; // in attesa di conferma unsigned char ConnectedOnce:1; // connessione ok unsigned char filler:2; // MSB } bits; } SMTPFlags = {0x00}; static WORD ResponseCode; /****************************************************************************** * External callback functions * ******************************************************************************/ // Main application must implement these callback functions extern WORD HTTPGetVar(BYTE var, WORD ref, BYTE* val); /****************************************************************************** * Internal functions ******************************************************************************/ /********************************************************************* * Function: BOOL SMTPBeginUsage(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: TRUE: If no SMTP operations are in progress and this application * has successfully taken ownership of the SMTP module * FALSE: If the SMTP module is currently being used by some other * application. * Call SMTPBeginUsage() some time later (after returning * to the main() program loop). * * Side Effects: None * * Overview: Call DNSBeginUsage() and make sure it returns TRUE before calling any * DNS APIs. Call DNSEndUsage() when this application no longer needs * the DNS module so that other applications may make use of it. * * Note: None ********************************************************************/ BOOL SMTPBeginUsage(void) { if(SMTPFlags.bits.SMTPInUse) { #if defined(SMTP_DEBUG) printf((ROMPC *)"\r\nB(0)"); #endif return FALSE; } SMTPFlags.Val = 0x00; SMTPFlags.bits.SMTPInUse = TRUE; TransportState = TRANSPORT_BEGIN; RXParserState = RX_BYTE_0; SMTPState = SMTP_HOME; memset((void*)&SMTPClient, 0x00, sizeof(SMTPClient)); SMTPClient.ServerPort = SMTP_PORT; #if defined(SMTP_DEBUG) printf((ROMPC *)"\r\nB(k)"); #endif return TRUE; } /********************************************************************* * Function: void SMTPEndUsage(void) * * PreCondition: SMTPBeginUsage() returned TRUE on a previous call. * * Input: None * * Output: SMTP_SUCCESS (0x0000): on success * SMTP_RESOLVE_ERROR (0x8000): if unable to resolve SMTP server * SMTP_CONNECT_ERROR (0x8001): if unable to connect to SMTP server * or connection lost * 1-199 and 300-999: last SMTP server response code * SMTP_ADDRESS_ERROR (0x8002): if unable to connect to SMTP server * * Side Effects: None * * Overview: Releases ownership of the SMTP module caused by a * previous call to SMTPBeginUsage() * * Note: None ********************************************************************/ WORD SMTPEndUsage(void) { #if defined(SMTP_DEBUG) printf((ROMPC *)"End"); #endif if(!SMTPFlags.bits.SMTPInUse) return 0xFFFF; // Release the DNS module, if in use if(TransportState == TRANSPORT_NAME_RESOLVE) DNSEndUsage(); // Release the TCP socket, if in use if(MySocket != INVALID_SOCKET) { TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; } // Release the SMTP module SMTPFlags.bits.SMTPInUse = FALSE; TransportState = TRANSPORT_HOME; if(SMTPFlags.bits.SentSuccessfully) { return 0; } else { return ResponseCode; } } /********************************************************************* * Function: void SMTPSendFile(void) ********************************************************************/ void SMTPSendFile(void) { BOOL lbTransmit; BYTE c; WORD_VAL HexNumber; WORD VarRef; BYTE Variable; int NumTrx = 0; enum _SM_SMTP { SM_SMTP_GET_READ, SM_SMTP_GET_DLE, SM_SMTP_GET_HANDLE, SM_SMTP_GET_VAR, SM_SMTP_GET_END, } smSMTPGet = SM_SMTP_GET_READ; smSMTPGet = SM_SMTP_GET_READ; while(TCPIsPutReady(MySocket) && (smSMTPGet != SM_SMTP_GET_END) && (NumTrx++ < 512)) { lbTransmit = FALSE; if(smSMTPGet != SM_SMTP_GET_VAR) { c = MPFSGet(); if(MPFSIsEOF()) { smSMTPGet = SM_SMTP_GET_END; MPFSGetEnd(); // TCPFlush(MySocket); } } switch(smSMTPGet) { case SM_SMTP_GET_READ: if ( c == SMTP_VAR_ESC_CHAR ) smSMTPGet = SM_SMTP_GET_DLE; else { lbTransmit = TRUE; if ((NumTrx++ > 400) && (c == 0x0A)) // spaccare in 2 blocchi ! { SMTPState--; NumTrx = 600; } } break; case SM_SMTP_GET_DLE: if ( c == SMTP_VAR_ESC_CHAR ) { lbTransmit = TRUE; smSMTPGet = SM_SMTP_GET_READ; } else { HexNumber.v[1] = c; smSMTPGet = SM_SMTP_GET_HANDLE; } break; case SM_SMTP_GET_HANDLE: HexNumber.v[0] = c; Variable = hexatob(HexNumber); smSMTPGet = SM_SMTP_GET_VAR; VarRef = SMTP_START_OF_VAR; break; case SM_SMTP_GET_VAR: VarRef = HTTPGetVar(Variable, VarRef, &c); lbTransmit = TRUE; if ( VarRef == SMTP_END_OF_VAR ) smSMTPGet = SM_SMTP_GET_READ; break; default: lbTransmit = FALSE; break; } if(lbTransmit) { TCPPut(MySocket, c); #if defined(SMTP_DEBUG) while(BusyUSART()); if (c > 0) putcUART(c); else printf((ROMPC *)"'%02x'",c); #endif } } } /********************************************************************* * Function: void SMTPSendSMS(void) ********************************************************************/ void SMTPSendSMS(void) { /* COMMENTED ... BYTE c; BYTE NumTrx = 0; int UsmsIdx = IE_SMS_START; c = ieprom_byte_r(UsmsIdx++); // write & incrementa pointer ieeprom while(TCPIsPutReady(MySocket) && (c) && (NumTrx++ < 250)) { TCPPut(MySocket, c); #if defined(SMTP_DEBUG) while(BusyUSART()); if (c > 0) putcUART(c); else printf((ROMPC *)"'%02x'",c); #endif c = ieprom_byte_r(UsmsIdx++); // write & incrementa pointer ieeprom } END OF COMMENT */ } /********************************************************************* * Function: void SMTPTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: Uses ARP module * * Overview: None * * Note: This is a work is in progress ********************************************************************/ void SMTPTask(void) { BYTE i; WORD w; BYTE vBase64Buffer[4]; static TICK Timer; static BYTE RXBuffer[4]; static ROM BYTE *ROMStrPtr, *ROMStrPtr2; static BYTE *RAMStrPtr; static WORD wAddressLength; static BYTE VarString[50]; static BYTE VarLen; static MPFS file; switch(TransportState) { case TRANSPORT_HOME: // SMTPBeginUsage() is the only function which will kick // the state machine into the next state break; case TRANSPORT_BEGIN: // Wait for the user to program all the pointers and then // call SMTPSendMail() if(!SMTPFlags.bits.ReadyToStart) break; // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) { #if defined(SMTP_DEBUG) printf((ROMPC *)" T1(0)"); #endif break; } #if defined(SMTP_DEBUG) printf((ROMPC *)"--T1"); #endif // Obtain the IP address associated with the SMTP mail server strcpypgm2ram(VarString, SMTP_SERVER); SMTPClient.szRAM = VarString; DNSResolve(SMTPClient.szRAM, DNS_TYPE_A); Timer = TickGet(); TransportState++; #if defined(SMTP_DEBUG) printf((ROMPC *)"--T2"); #endif break; case TRANSPORT_NAME_RESOLVE: // Wait for the DNS server to return the requested IP address if(!DNSIsResolved(&SMTPServer.IPAddr)) { // Timeout after 6 seconds of unsuccessful DNS resolution if(TickGet() - Timer > 6*TICK_SECOND) { ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_ERROR; DNSEndUsage(); #if defined(SMTP_DEBUG) printf((ROMPC *)">to"); #endif } break; } #if defined(SMTP_DEBUG) printf((ROMPC *)"k"); #endif // Release the DNS module, we no longer need it if(!DNSEndUsage()) { #if defined(SMTP_DEBUG) printf((ROMPC *)">ko"); #endif // An invalid IP address was returned from the DNS // server. Quit and fail permanantly if host is not valid. ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_ERROR; break; } #if defined(SMTP_DEBUG) printf((ROMPC *)"-->"); IPAddressToString(&SMTPServer.IPAddr, VarString); putsUART(VarString); // attende porta libera e poi scrive stringa #endif TransportState++; // No need to break here Timer = TickGet(); ARPResolve(&SMTPServer.IPAddr); #if defined(SMTP_DEBUG) printf((ROMPC *)"--T3"); #endif case TRANSPORT_NAME_RESOLVE_ARP: if(!ARPIsResolved(&SMTPServer.IPAddr, &SMTPServer.MACAddr)) // Timeout after 6 seconds of unsuccessful DNS resolution if(TickGet() - Timer > 6*TICK_SECOND) { ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_ERROR; #if defined(SMTP_DEBUG) printf((ROMPC *)">to"); #endif break; } TransportState++; break; case TRANSPORT_OBTAIN_SOCKET: #if defined(SMTP_DEBUG) printf((ROMPC *)"--T4"); #endif // Connect a TCP socket to the remote SMTP server // MySocket = TCPOpen(SMTPServer.Val, TCP_OPEN_IP_ADDRESS, SMTPClient.ServerPort, TCP_PURPOSE_DEFAULT); MySocket = TCPConnect(&SMTPServer, SMTPClient.ServerPort); // Abort operation if no TCP sockets are available // If this ever happens, incrementing add some more // TCP_PURPOSE_DEFAULT sockets in TCPIPConfig.h if(MySocket == INVALID_SOCKET) { #if defined(SMTP_DEBUG) printf((ROMPC *)"(0)"); #endif ResponseCode = SMTP_SOCKET_ERROR; TransportState = TRANSPORT_ERROR; break; } TransportState++; Timer = TickGet(); // No break; fall into TRANSPORT_SOCKET_OBTAINED #if defined(SMTP_DEBUG) printf((ROMPC *)"--T5"); #endif case TRANSPORT_SOCKET_OBTAINED: if(!TCPIsConnected(MySocket)) { // Don't stick around in the wrong state if the // server was connected, but then disconnected us. // Also time out if we can't establish the connection // to the SMTP server if(SMTPFlags.bits.ConnectedOnce || ((TickGet()-Timer) > (SMTP_SERVER_REPLY_TIMEOUT))) { ResponseCode = SMTP_CONNECT_ERROR; TransportState = TRANSPORT_CLOSE; #if defined(SMTP_DEBUG) printf((ROMPC *)"(0)"); #endif } break; } SMTPFlags.bits.ConnectedOnce = TRUE; #if defined(SMTP_DEBUG) // printf((ROMPC *)">"); #endif // See if the server sent us anything while(TCPIsGetReady(MySocket)) { TCPGet(MySocket, &i); #if defined(SMTP_DEBUG) // printf((ROMPC *)"_"); while(BusyUSART()); if (i > 0) putcUART(i); else printf((ROMPC *)"'%02x'",i); #endif switch(RXParserState) { case RX_BYTE_0: case RX_BYTE_1: case RX_BYTE_2: RXBuffer[RXParserState] = i; RXParserState++; break; case RX_BYTE_3: switch(i) { case ' ': SMTPFlags.bits.RXSkipResponse = FALSE; RXParserState++; break; case '-': SMTPFlags.bits.RXSkipResponse = TRUE; RXParserState++; break; case '\r': RXParserState = RX_SEEK_LF; break; } break; case RX_SEEK_CR: if(i == '\r') RXParserState++; break; case RX_SEEK_LF: // If we received the whole command if(i == '\n') { RXParserState = RX_BYTE_0; if(!SMTPFlags.bits.RXSkipResponse) { // The server sent us a response code // Null terminate the ASCII reponse code so we can convert it to an integer RXBuffer[3] = 0; ResponseCode = atoi((char*)RXBuffer); // Handle the response switch(SMTPState) { case SMTP_HELO_ACK: if(ResponseCode >= 200u && ResponseCode <= 299u) { // if(SMTPClient.szRAM || SMTPClient.Username.szROM) SMTPState = SMTP_AUTH_LOGIN; // else // SMTPState = SMTP_MAILFROM; } else SMTPState = SMTP_QUIT_INIT; break; case SMTP_AUTH_LOGIN_ACK: case SMTP_AUTH_USERNAME_ACK: if(ResponseCode == 334u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_AUTH_PASSWORD_ACK: if(ResponseCode == 235u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_HOME: case SMTP_MAILFROM_ACK: case SMTP_RCPTTO_ACK: case SMTP_RCPTTOCC_ACK: case SMTP_RCPTTOBCC_ACK: if(ResponseCode >= 200u && ResponseCode <= 299u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_DATA_ACK: if(ResponseCode == 354u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_DATA_BODY_ACK: if(ResponseCode >= 200u && ResponseCode <= 299u) SMTPFlags.bits.SentSuccessfully = TRUE; SMTPState = SMTP_QUIT_INIT; break; } } } else if(i != '\r') RXParserState--; break; } } // Generate new data in the TX buffer, as needed, if possible // if(TCPIsPutReady(MySocket) < 64u) if(!TCPIsPutReady(MySocket)) break; switch(SMTPState) { case SMTP_HELO: strcpypgm2ram(VarString, (ROM char *) "HELO " DEFAULT_NETBIOS_NAME "\r\n"); goto SmtpTaskDetailString; case SMTP_AUTH_LOGIN: SMTPState += 6; // bypass login , comment this line if SMTP requires login & password break; // bypass login , comment this line if SMTP requires login & password // Note: This state is only entered from SMTP_HELO_ACK if the application // has specified a Username to use (either SMTPClient.Username.szROM or // SMTPClient.szRAM is non-NULL) strcpypgm2ram(VarString, (ROM char *) "AUTH LOGIN\r\n"); goto SmtpTaskDetailString; case SMTP_AUTH_USERNAME: // Base 64 encode and transmit the username. strcpypgm2ram((VarString + 20), (ROM char *) SMTP_USER); // USER NAME SMTPClient.szRAM = (VarString + 20); // usa dal byte 20 in su RAMStrPtr = SMTPClient.szRAM; // da 0 a SmtpEncodeTransmit: w = strlen((char*)RAMStrPtr); // LENGTH OF USER NAME VarLen = 0; while(w) { i = 0; while((i < w) && (i < 3)) { vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; Base64Encode(vBase64Buffer, i, &VarString[VarLen], sizeof(vBase64Buffer)); VarLen += 4; } VarString[VarLen++] = '\r'; VarString[VarLen++] = '\n'; VarString[VarLen] = 0x00; goto SmtpTaskDetailArray; case SMTP_AUTH_PASSWORD: // Base 64 encode and transmit the password strcpypgm2ram((VarString + 20), (ROM char *) SMTP_PASSWORD); SMTPClient.szRAM = (VarString + 20); RAMStrPtr = SMTPClient.szRAM; goto SmtpEncodeTransmit; case SMTP_MAILFROM: //strcpypgm2ram(VarString, (ROM char *) "MAIL FROM:<" SMTP_FROM ">\r\n" ); strcpypgm2ram(VarString, (ROM char *) SMTP_FROM); //sprintf(info_sender ,"Send from : <%s>\r\n",SMTP_FROM ); //strcpypgm2ram(VarString, (ROM char *) info_sender); goto SmtpTaskDetailString; case SMTP_RCPTTO_INIT: SmtpTaskRCPT: strcpypgm2ram(VarString, (ROM char *) SMTP_ADDRESSES); file = MPFSOpen(VarString); if ((file != MPFS_INVALID ) && (file != MPFS_NOT_AVAILABLE )) { file = MPFSSkip((MPFS_OFFSET)(SMTPClient.Flag.SendToAddress * SMTP_ADDRESSES_LEN) ); // file += (SMTPClient.Flag.SendToAddress) * SMTP_ADDRESSES_LEN; strcpypgm2ram(VarString, (ROM char *) "RCPT TO:"); w = 8; // punta alla fine di RCPT TO: MPFSGetBegin(file); do { i = MPFSGet(); VarString[w++]= i; } while ((i != '>') && (w < (SMTP_ADDRESSES_LEN + 8))); VarString[w++] = 0x0D; // CR VarString[w++] = 0x0A; // LF VarString[w++] = 0x00; // end of string MPFSGetEnd(); } else { ResponseCode = SMTP_ADDRESS_ERROR; strcpypgm2ram(VarString, (ROM char *) "RCPT TO:\r\n"); } MPFSClose(); goto SmtpTaskDetailString; case SMTP_RCPTTO: case SMTP_RCPTTOCC: case SMTP_RCPTTOBCC: TCPFlush(MySocket); SMTPState++; break; case SMTP_RCPTTO_ISDONE: SMTPState++; //No break case SMTP_RCPTTOCC_INIT: if (SMTPClient.Flag.SendToAddres1) { SMTPClient.Flag.SendToAddress = SMTPClient.Flag.SendToAddres1; SMTPClient.Flag.SendToAddres1 = 0; goto SmtpTaskRCPT; } SMTPState = SMTP_RCPTTOBCC_INIT; break; case SMTP_RCPTTOCC_ISDONE: SMTPState++; //No break case SMTP_RCPTTOBCC_INIT: if (SMTPClient.Flag.SendToAddres2) { SMTPClient.Flag.SendToAddress = SMTPClient.Flag.SendToAddres2; SMTPClient.Flag.SendToAddres2 = 0; goto SmtpTaskRCPT; } SMTPState = SMTP_DATA; break; case SMTP_RCPTTOBCC_ISDONE: SMTPState++; //No break case SMTP_DATA: strcpypgm2ram(VarString, (ROM char *) "DATA\r\n"); goto SmtpTaskDetailString; case SMTP_DATA_HEADER: if (!SMTPClient.Flag.SendMessgType) { SMTPState++; strcpypgm2ram(VarString, (ROM char *) SMS_FREE_FROM "\r\n"); goto SmtpTaskDetailString; } strcpypgm2ram(VarString, (ROM char *) SMTP_MSG_INDEX); file = MPFSOpen(VarString); if ((file != MPFS_INVALID ) && (file != MPFS_NOT_AVAILABLE )) { file = MPFSSkip((MPFS_OFFSET)(SMTPClient.Flag.SendMessgType * SMTP_MSG_INDEX_LEN) ); // file += (SMTPClient.Flag.SendMessgType) * SMTP_MSG_INDEX_LEN; MPFSGetBegin(file); for ( w = 0; w < (SMTP_MSG_INDEX_LEN - 2); w++ ) // escluso CRLF VarString[w]= MPFSGet(); VarString[++w] = 0x00; MPFSGetEnd(); MPFSClose(); SMTPState++; break; } else { #if defined(SMTP_DEBUG) printf((ROMPC *)"\r\n>notfnd " SMTP_MSG_INDEX); #endif ResponseCode = SMTP_MSGINDX_ERROR; } MPFSClose(); goto SmtpTaskDetailString; case SMTP_DATA_BODY_INIT: #if defined(SMTP_DEBUG) printf((ROMPC *)"\r\n>fnd "); putsUART(VarString); // attende porta libera e poi scrive stringa #endif file = MPFSOpen(VarString); MPFSGetBegin(file); SMTPState++; // No break here case SMTP_DATA_BODY: #if defined(SMTP_DEBUG) printf((ROMPC *)">"); #endif if (!SMTPClient.Flag.SendMessgType) SMTPSendSMS(); else if ((file != MPFS_INVALID ) && (file != MPFS_NOT_AVAILABLE )) { #if defined(SMTP_DEBUG) printf((ROMPC *)"."); #endif SMTPSendFile(); #if defined(SMTP_DEBUG) printf((ROMPC *)"<"); #endif } else { ResponseCode = SMTP_MSGFILE_ERROR; strcpypgm2ram(VarString, (ROM char *) "NOTFOUND"); MPFSClose(); goto SmtpTaskDetailString; } #if defined(SMTP_DEBUG) printf((ROMPC *)"-"); #endif TCPFlush(MySocket); SMTPState++; break; case SMTP_DATA_BODY_END: MPFSClose(); strcpypgm2ram(VarString, (ROM char *) "\r\n.\r\n"); goto SmtpTaskDetailString; case SMTP_QUIT_INIT: strcpypgm2ram(VarString, (ROM char *) "QUIT\r\n"); goto SmtpTaskDetailString; case SMTP_QUIT: ResponseCode = SMTP_SUCCESS; TransportState = TRANSPORT_CLOSE; break; // ------------------------------------------------------------------ SmtpTaskDetailString: VarLen = strlen(VarString); SmtpTaskDetailArray: #if defined(SMTP_DEBUG) putsUART(VarString); // attende porta libera e poi scrive stringa #endif RXParserState = RX_BYTE_0; if (TCPIsPutReady(MySocket)) { if (TCPPutArray(MySocket, VarString, VarLen)) { TCPFlush(MySocket); SMTPState++; } else { #if defined(SMTP_DEBUG) printf((ROMPC *)"!(ko)"); #endif ResponseCode = SMTP_TCPPUT_ERROR; TCPFlush(MySocket); } } else { #if defined(SMTP_DEBUG) printf((ROMPC *)"!(kp)"); #endif ResponseCode = SMTP_TCPNRDY_ERROR; SMTPState++; } break; // ------------------------------------------------------------------ } break; case TRANSPORT_CLOSE: // Close the socket so it can be used by other modules TCPDisconnect(MySocket); case TRANSPORT_ERROR: MySocket = INVALID_SOCKET; SMTPEndUsage(); // Go back to doing nothing TransportState = TRANSPORT_HOME; #if defined(SMTP_DEBUG) printf((ROMPC *)" CLOSE"); #endif break; } } void SMTPSendMail(WORD mflag) { SMTPClient.Flag.Val = mflag; // SMTPClient->Flag = mflag; SMTPFlags.bits.ReadyToStart = TRUE; } BOOL SMTPIsBusy(void) { return TransportState != TRANSPORT_HOME; } WORD SMTPIsPutReady(void) { if(SMTPState != SMTP_DATA_BODY) return 0; return TCPIsPutReady(MySocket); } BYTE SMTPGetState(void) { return ((char) SMTPFlags.Val); } WORD SMTPGetResponse(void) { return ResponseCode; } #endif //#if defined(STACK_USE_SMTP_CLIENT)