/***************************************************************************** Function: bool TCPIP_SMTP_Put(char c) Description: Writes a single byte to the SMTP client. Precondition: TCPIP_SMTP_UsageBegin returned true on a previous call. Parameters: c - The byte to be written Return Values: true - The byte was successfully written false - The byte was not written, most likely because the buffer was full Remarks: This function should only be called externally when the SMTP client is generating an on-the-fly message. (That is, TCPIP_SMTP_MailSend was called with SMTPClient.Body set to NULL.) ***************************************************************************/ bool TCPIP_SMTP_Put(char c) { if(CRPeriod.State == CR_PERIOD_NEED_INSERTION) { if(TCPIP_TCP_Put(MySocket, '.')) CRPeriod.State = CR_PERIOD_SEEK_CR; else return false; } switch(CRPeriod.State) { case CR_PERIOD_SEEK_CR: if(c == '\r') CRPeriod.State++; break; case CR_PERIOD_SEEK_LF: if(c == '\n') CRPeriod.State++; else if(c != '\r') CRPeriod.State--; break; case CR_PERIOD_SEEK_PERIOD: if(c == '.') CRPeriod.State++; // CR_PERIOD_NEED_INSERTION else if(c == '\r') CRPeriod.State--; else CRPeriod.State = CR_PERIOD_SEEK_CR; break; // Default case needed to supress compiler diagnostics // (CR_PERIOD_NEED_INSERTION state already handled above) default: break; } if(!TCPIP_TCP_Put(MySocket, c)) return false; return true; }
static void TCPIP_SMTP_ClientProcess(void) { uint8_t i; uint16_t w; uint8_t vBase64Buffer[4]; static uint32_t SMTPTimer; static uint8_t RXBuffer[4]; static const uint8_t *ROMStrPtr, *ROMStrPtr2; static const uint8_t *RAMStrPtr; static uint16_t wAddressLength; TCPIP_DNS_RESULT dnsRes; DNS_RESOLVE_TYPE dnsType; switch(TransportState) { case TRANSPORT_HOME: // TCPIP_SMTP_UsageBegin() 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 TCPIP_SMTP_MailSend() if(!SMTPFlags.bits.ReadyToStart) { break; } SMTPClient.Server = FindEmailServer(&SMTPClient, &dnsType); // See if we found a hostname anywhere which we could resolve if(!(SMTPClient.Server)) { ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; break; } // check for a plain IP address if(TCPIP_Helper_StringToIPAddress(SMTPClient.Server, &SMTPServer)) { TransportState = TRANSPORT_OBTAIN_SOCKET; break; } // use DNS to resolve the name TCPIP_DNS_Resolve(SMTPClient.Server, dnsType); SMTPTimer = SYS_TMR_TickCountGet(); TransportState++; break; case TRANSPORT_NAME_RESOLVE: // Wait for the DNS server to return the requested IP address dnsRes = TCPIP_DNS_IsResolved((const char*)SMTPClient.Server,&SMTPServer); if(dnsRes == DNS_RES_PENDING) { break; } if(dnsRes < 0) { // some error occurred ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; break; } // DNS_RES_OK TransportState++; // No need to break here case TRANSPORT_OBTAIN_SOCKET: // Connect a TCP socket to the remote SMTP server MySocket = TCPIP_TCP_ClientOpen(IP_ADDRESS_TYPE_IPV4, SMTPClient.ServerPort, (IP_MULTI_ADDRESS*)&SMTPServer.Val); // Abort operation if no TCP socket could be opened. // If this ever happens, you need to update your tcp_config.h if(MySocket == INVALID_SOCKET) break; TCPIP_TCP_SignalHandlerRegister(MySocket, TCPIP_TCP_SIGNAL_RX_DATA, _SMTPSocketRxSignalHandler, 0); TransportState++; SMTPTimer = SYS_TMR_TickCountGet(); // No break; fall into TRANSPORT_SOCKET_OBTAINED case TRANSPORT_SOCKET_OBTAINED: if(!TCPIP_TCP_IsConnected(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 || ((SYS_TMR_TickCountGet()-SMTPTimer) > (TCPIP_SMTP_SERVER_REPLY_TIMEOUT * SYS_TMR_TickCounterFrequencyGet()))) { ResponseCode = SMTP_CONNECT_ERROR; TransportState = TRANSPORT_CLOSE; } break; } SMTPFlags.bits.ConnectedOnce = true; // See if the server sent us anything while(TCPIP_TCP_GetIsReady(MySocket)) { TCPIP_TCP_Get(MySocket, &i); 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.Username) 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; // Default case needed to supress compiler diagnostics default: break; } } } else if(i != '\r') RXParserState--; break; } } // Generate new data in the TX buffer, as needed, if possible if(TCPIP_TCP_PutIsReady(MySocket) < 64u) break; switch(SMTPState) { case SMTP_HELO: if(SMTPClient.Username == NULL) TCPIP_TCP_StringPut(MySocket, (uint8_t*)"HELO MCHPBOARD\r\n"); else TCPIP_TCP_StringPut(MySocket, (uint8_t*)"EHLO MCHPBOARD\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_AUTH_LOGIN: // Note: This state is only entered from SMTP_HELO_ACK if the application // has specified a Username to use (SMTPClient.Username is non-NULL) TCPIP_TCP_StringPut(MySocket, (uint8_t*)"AUTH LOGIN\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_AUTH_USERNAME: // Base 64 encode and transmit the username. RAMStrPtr = (uint8_t*)SMTPClient.Username; w = strlen((char*)RAMStrPtr); while(w) { i = 0; while((i < w) && (i < sizeof(vBase64Buffer)*3/4)) { vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; TCPIP_Helper_Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer)); TCPIP_TCP_ArrayPut(MySocket, vBase64Buffer, sizeof(vBase64Buffer)); } TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_AUTH_PASSWORD: // Base 64 encode and transmit the password RAMStrPtr = (uint8_t*)SMTPClient.Password; w = strlen((char*)RAMStrPtr); while(w) { i = 0; while((i < w) && (i < sizeof(vBase64Buffer)*3/4)) { vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; TCPIP_Helper_Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer)); TCPIP_TCP_ArrayPut(MySocket, vBase64Buffer, sizeof(vBase64Buffer)); } TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_MAILFROM: // Send MAIL FROM header. Note that this is for the SMTP server validation, // not what actually will be displayed in the recipients mail client as a // return address. TCPIP_TCP_StringPut(MySocket, (uint8_t*)"MAIL FROM:<"); RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.From, &wAddressLength); TCPIP_TCP_ArrayPut(MySocket, RAMStrPtr, wAddressLength); TCPIP_TCP_StringPut(MySocket, (uint8_t*)">\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_RCPTTO_INIT: // See if there are any (To) recipients to process if(SMTPClient.To) { RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.To, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTO; break; } } SMTPState = SMTP_RCPTTOCC_INIT; break; case SMTP_RCPTTO: case SMTP_RCPTTOCC: case SMTP_RCPTTOBCC: TCPIP_TCP_StringPut(MySocket, (uint8_t*)"RCPT TO:<"); TCPIP_TCP_ArrayPut(MySocket, RAMStrPtr, wAddressLength); TCPIP_TCP_StringPut(MySocket, (uint8_t*)">\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_RCPTTO_ISDONE: // See if we have any more (To) recipients to process // If we do, we must roll back a couple of states RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTO; break; } // All done with To field SMTPState++; //No break case SMTP_RCPTTOCC_INIT: // See if there are any Carbon Copy (CC) recipients to process if(SMTPClient.CC) { RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.CC, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOCC; break; } } SMTPState = SMTP_RCPTTOBCC_INIT; break; case SMTP_RCPTTOCC_ISDONE: // See if we have any more Carbon Copy (CC) recipients to process // If we do, we must roll back a couple of states RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOCC; break; } // All done with CC field SMTPState++; //No break case SMTP_RCPTTOBCC_INIT: // See if there are any Blind Carbon Copy (BCC) recipients to process if(SMTPClient.BCC) { RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.BCC, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOBCC; break; } } // All done with BCC field SMTPState = SMTP_DATA; break; case SMTP_RCPTTOBCC_ISDONE: // See if we have any more Blind Carbon Copy (CC) recipients to process // If we do, we must roll back a couple of states RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOBCC; break; } // All done with BCC field SMTPState++; //No break case SMTP_DATA: TCPIP_TCP_StringPut(MySocket, (uint8_t*)"DATA\r\n"); SMTPState++; PutHeadersState = PUTHEADERS_FROM_INIT; TCPIP_TCP_Flush(MySocket); break; case SMTP_DATA_HEADER: while((PutHeadersState != PUTHEADERS_DONE) && (TCPIP_TCP_PutIsReady(MySocket) > 64u)) { switch(PutHeadersState) { case PUTHEADERS_FROM_INIT: if(SMTPClient.From) { PutHeadersState = PUTHEADERS_FROM; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"From: "); } else { PutHeadersState = PUTHEADERS_TO_INIT; } break; case PUTHEADERS_FROM: SMTPClient.From = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.From); if(*SMTPClient.From == 0u) PutHeadersState = PUTHEADERS_TO_INIT; break; case PUTHEADERS_TO_INIT: if(SMTPClient.To) { PutHeadersState = PUTHEADERS_TO; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\nTo: "); } else { PutHeadersState = PUTHEADERS_CC_INIT; } break; case PUTHEADERS_TO: SMTPClient.To = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.To); if(*SMTPClient.To == 0u) PutHeadersState = PUTHEADERS_CC_INIT; break; case PUTHEADERS_CC_INIT: if(SMTPClient.CC) { PutHeadersState = PUTHEADERS_CC; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\nCC: "); } else { PutHeadersState = PUTHEADERS_SUBJECT_INIT; } break; case PUTHEADERS_CC: SMTPClient.CC = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.CC); if(*SMTPClient.CC == 0u) PutHeadersState = PUTHEADERS_SUBJECT_INIT; break; case PUTHEADERS_SUBJECT_INIT: if(SMTPClient.Subject) { PutHeadersState = PUTHEADERS_SUBJECT; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\nSubject: "); } else { PutHeadersState = PUTHEADERS_OTHER_INIT; } break; case PUTHEADERS_SUBJECT: SMTPClient.Subject = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.Subject); if(*SMTPClient.Subject == 0u) PutHeadersState = PUTHEADERS_OTHER_INIT; break; case PUTHEADERS_OTHER_INIT: TCPIP_TCP_ArrayPut(MySocket, (uint8_t*)"\r\n", 2); if(SMTPClient.OtherHeaders) { PutHeadersState = PUTHEADERS_OTHER; } else { TCPIP_TCP_ArrayPut(MySocket, (uint8_t*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } break; case PUTHEADERS_OTHER: SMTPClient.OtherHeaders = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.OtherHeaders); if(*SMTPClient.OtherHeaders == 0u) { TCPIP_TCP_ArrayPut(MySocket, (uint8_t*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } break; // Default case needed to supress compiler diagnostics default: break; } } TCPIP_TCP_Flush(MySocket); break; case SMTP_DATA_BODY_INIT: SMTPState++; RAMStrPtr = (uint8_t*)SMTPClient.Body; ROMStrPtr2 = (const uint8_t*)"\r\n.\r\n"; CRPeriod.Pos = NULL; if(RAMStrPtr) CRPeriod.Pos = (uint8_t*)strstr((char*)RAMStrPtr, (const char*)"\r\n."); // No break here case SMTP_DATA_BODY: if(SMTPClient.Body) { if(*ROMStrPtr2) { // Put the application data, doing the transparancy replacement of "\r\n." with "\r\n.." while(CRPeriod.Pos) { CRPeriod.Pos += 3; RAMStrPtr += TCPIP_TCP_ArrayPut(MySocket, RAMStrPtr, CRPeriod.Pos-RAMStrPtr); if(RAMStrPtr == CRPeriod.Pos) { if(!TCPIP_TCP_Put(MySocket, '.')) { CRPeriod.Pos -= 3; break; } } else { CRPeriod.Pos -= 3; break; } CRPeriod.Pos = (uint8_t*)strstr((char*)RAMStrPtr, (const char*)"\r\n."); } // If we get down here, either all replacements have been made or there is no remaining space in the TCP output buffer RAMStrPtr = TCPIP_TCP_StringPut(MySocket, RAMStrPtr); ROMStrPtr2 = TCPIP_TCP_StringPut(MySocket, (uint8_t*)ROMStrPtr2); TCPIP_TCP_Flush(MySocket); } } else { if(SMTPFlags.bits.ReadyToFinish) { if(*ROMStrPtr2) { ROMStrPtr2 = TCPIP_TCP_StringPut(MySocket, (uint8_t*)ROMStrPtr2); TCPIP_TCP_Flush(MySocket); } } } if(*ROMStrPtr2 == 0u) { SMTPState++; } break; case SMTP_QUIT_INIT: SMTPState++; ROMStrPtr = (const uint8_t*)"QUIT\r\n"; // No break here case SMTP_QUIT: if(*ROMStrPtr) { ROMStrPtr = TCPIP_TCP_StringPut(MySocket, (uint8_t*)ROMStrPtr); TCPIP_TCP_Flush(MySocket); } if(*ROMStrPtr == 0u) { TransportState = TRANSPORT_CLOSE; } break; // Default case needed to supress compiler diagnostics default: break; } break; case TRANSPORT_CLOSE: // Close the socket so it can be used by other modules TCPIP_TCP_Close(MySocket); MySocket = INVALID_SOCKET; // Go back to doing nothing TransportState = TRANSPORT_HOME; break; } }
void TCPIP_HTTP_Print_(HTTP_CONN_HANDLE connHandle) { TCP_SOCKET sktHTTP = TCPIP_HTTP_CurrentConnectionSocketGet(connHandle); TCPIP_TCP_Put(sktHTTP, '~'); return; }