?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
2 *
3 * Simple Mail Transfer Protocol (SMTP) Client
4 * Module for Microchip TCP/IP Stack
5 * -Provides ability to send Emails
6 * -Reference: RFC 2821
7 *
8 *********************************************************************
9 * FileName: SMTP.c
10 * Dependencies: TCP, ARP, DNS, Tick
11 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
12 * Compiler: Microchip C32 v1.05 or higher
13 * Microchip C30 v3.12 or higher
14 * Microchip C18 v3.30 or higher
15 * HI-TECH PICC-18 PRO 9.63PL2 or higher
16 * Company: Microchip Technology, Inc.
17 *
18 * Software License Agreement
19 *
20 * Copyright (C) 2002-2009 Microchip Technology Inc. All rights
21 * reserved.
22 *
23 * Microchip licenses to you the right to use, modify, copy, and
24 * distribute:
25 * (i) the Software when embedded on a Microchip microcontroller or
26 * digital signal controller product ("Device") which is
27 * integrated into Licensee's product; or
28 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
29 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
30 * used in conjunction with a Microchip ethernet controller for
31 * the sole purpose of interfacing with the ethernet controller.
32 *
33 * You should refer to the license agreement accompanying this
34 * Software for additional information regarding your rights and
35 * obligations.
36 *
37 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
38 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
39 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
40 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
41 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
42 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
43 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
44 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
45 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
46 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
47 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
48 *
49 *
50 * Author Date Comment
51 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52 * Howard Schlunder 3/03/06 Original
53 * Howard Schlunder 11/2/06 Vastly improved for release
54 ********************************************************************/
55 #define __SMTP_C
56  
57 #include "TCPIPConfig.h"
58  
59 #if defined(STACK_USE_SMTP_CLIENT)
60  
61 #include "TCPIP Stack/TCPIP.h"
62  
63  
64 /****************************************************************************
65 Section:
66 SMTP Client Configuration Parameters
67 ***************************************************************************/
68 #define SMTP_PORT 25 // Default port to use when unspecified
69 #define SMTP_SERVER_REPLY_TIMEOUT (TICK_SECOND*8) // How long to wait before assuming the connection has been dropped (default 8 seconds)
70  
71  
72 /****************************************************************************
73 Section:
74 SMTP Client Public Variables
75 ***************************************************************************/
76 // The global set of SMTP_POINTERS.
77 // Set these parameters after calling SMTPBeginUsage successfully.
78 SMTP_POINTERS SMTPClient;
79  
80 /****************************************************************************
81 Section:
82 SMTP Client Internal Variables
83 ***************************************************************************/
84 static IP_ADDR SMTPServer; // IP address of the remote SMTP server
85 static TCP_SOCKET MySocket = INVALID_SOCKET; // Socket currently in use by the SMTP client
86  
87 // State machine for the CR LF Period replacement
88 // Used by SMTPPut to transparently replace "\r\n." with "\r\n.."
89 static union
90 {
91 BYTE *Pos;
92 enum
93 {
94 CR_PERIOD_SEEK_CR = 0, // Idle state, waiting for '\r'
95 CR_PERIOD_SEEK_LF, // "\r" has been written, so check next byte for '\n'
96 CR_PERIOD_SEEK_PERIOD, // "\r\n" has been written, so check next byte for '.'
97 CR_PERIOD_NEED_INSERTION // "\r\n." has been written, so an additional '.'
98 // must be written before the next byte.
99 } State;
100 } CRPeriod;
101  
102 // State of the transport for the SMTP Client
103 static enum
104 {
105 TRANSPORT_HOME = 0, // Idle state
106 TRANSPORT_BEGIN, // Preparing to make connection
107 TRANSPORT_NAME_RESOLVE, // Resolving the SMTP server address
108 TRANSPORT_OBTAIN_SOCKET, // Obtaining a socket for the SMTP connection
109 #if defined(STACK_USE_SSL_CLIENT)
110 TRANSPORT_SECURING_SOCKET, // Securing the socket for the SMTP over SSL connection
111 #endif
112 TRANSPORT_SOCKET_OBTAINED, // SMTP connection successful
113 TRANSPORT_CLOSE // STMP socket is closed
114 } TransportState = TRANSPORT_HOME;
115  
116 // Message state machine for the SMTP Client
117 static enum
118 {
119 SMTP_HOME = 0, // Idle start state for SMTP client (application is preparing message)
120 SMTP_HELO, // HELO is being sent to server
121 SMTP_HELO_ACK, // Received an ACK for the HELO
122 SMTP_AUTH_LOGIN, // Requesting to log in
123 SMTP_AUTH_LOGIN_ACK, // Log in request accepted
124 SMTP_AUTH_USERNAME, // Sending user name
125 SMTP_AUTH_USERNAME_ACK, // User name accepted
126 SMTP_AUTH_PASSWORD, // Sending password
127 SMTP_AUTH_PASSWORD_ACK, // Password was accepted
128 SMTP_MAILFROM, // Sending inital MAIL FROM command
129 SMTP_MAILFROM_ACK, // MAIL FROM was accepted
130 SMTP_RCPTTO_INIT, // Preparing to send RCPT TO
131 SMTP_RCPTTO, // Sending RCPT TO command
132 SMTP_RCPTTO_ACK, // RCPT TO was accepted
133 SMTP_RCPTTO_ISDONE, // Done sending RCPT TO commands
134 SMTP_RCPTTOCC_INIT, // Preparing to send RCPT TO CC commands
135 SMTP_RCPTTOCC, // Sending RCPT TO CC commands
136 SMTP_RCPTTOCC_ACK, // RCPT TO CC was accepted
137 SMTP_RCPTTOCC_ISDONE, // Done sending RCPT TO CC
138 SMTP_RCPTTOBCC_INIT, // Preparing to send RCPT TO BCC commands
139 SMTP_RCPTTOBCC, // Sending RCPT TO BCC commands
140 SMTP_RCPTTOBCC_ACK, // RCPT TO BCC was accepted
141 SMTP_RCPTTOBCC_ISDONE, // Done sending RCPT TO BCC
142 SMTP_DATA, // Sending DATA command
143 SMTP_DATA_ACK, // DATA command accpted
144 SMTP_DATA_HEADER, // Sending message headers
145 SMTP_DATA_BODY_INIT, // Preparing for message body
146 SMTP_DATA_BODY, // Sending message body
147 SMTP_DATA_BODY_ACK, // Message body accepted
148 SMTP_QUIT_INIT, // Sending QUIT command
149 SMTP_QUIT // QUIT accepted, connection closing
150 } SMTPState;
151  
152 // State machine for writing the SMTP message headers
153 static enum
154 {
155 PUTHEADERS_FROM_INIT = 0, // Preparing to send From header
156 PUTHEADERS_FROM, // Sending From header
157 PUTHEADERS_TO_INIT, // Preparing to send To header
158 PUTHEADERS_TO, // Sending To header
159 PUTHEADERS_CC_INIT, // Preparing to send CC header
160 PUTHEADERS_CC, // Sending CC header
161 PUTHEADERS_SUBJECT_INIT, // Preparing to send Subject header
162 PUTHEADERS_SUBJECT, // Sending Subject header
163 PUTHEADERS_OTHER_INIT, // Preparing to send additional headers
164 PUTHEADERS_OTHER, // Sending additional headers
165 PUTHEADERS_DONE // Done writing all headers
166 } PutHeadersState;
167  
168 // State machine for parsing incoming responses
169 static enum
170 {
171 RX_BYTE_0 = 0,
172 RX_BYTE_1,
173 RX_BYTE_2,
174 RX_BYTE_3,
175 RX_SEEK_CR,
176 RX_SEEK_LF
177 } RXParserState;
178  
179 // Internal flags used by the SMTP Client
180 static union
181 {
182 BYTE Val;
183 struct
184 {
185 unsigned char RXSkipResponse:1;
186 unsigned char SMTPInUse:1;
187 unsigned char SentSuccessfully:1;
188 unsigned char ReadyToStart:1;
189 unsigned char ReadyToFinish:1;
190 unsigned char ConnectedOnce:1;
191 unsigned char filler:2;
192 } bits;
193 } SMTPFlags = {0x00};
194  
195 // Response code from server when an error exists
196 static WORD ResponseCode;
197  
198 /****************************************************************************
199 Section:
200 SMTP Client Internal Function Prototypes
201 ***************************************************************************/
202 static BYTE *FindEmailAddress(BYTE *str, WORD *wLen);
203 static ROM BYTE *FindROMEmailAddress(ROM BYTE *str, WORD *wLen);
204  
205 /****************************************************************************
206 Section:
207 SMTP Function Implementations
208 ***************************************************************************/
209  
210 /*****************************************************************************
211 Function:
212 BOOL SMTPBeginUsage(void)
213  
214 Summary:
215 Requests control of the SMTP client module.
216  
217 Description:
218 Call this function before calling any other SMTP Client APIs. This
219 function obtains a lock on the SMTP Client, which can only be used by
220 one stack application at a time. Once the application is finished
221 with the SMTP client, it must call SMTPEndUsage to release control
222 of the module to any other waiting applications.
223  
224 This function initializes all the SMTP state machines and variables
225 back to their default state.
226  
227 Precondition:
228 None
229  
230 Parameters:
231 None
232  
233 Return Values:
234 TRUE - The application has successfully obtained control of the module
235 FALSE - The SMTP module is in use by another application. Call
236 SMTPBeginUsage again later, after returning to the main program loop
237 ***************************************************************************/
238 BOOL SMTPBeginUsage(void)
239 {
240 if(SMTPFlags.bits.SMTPInUse)
241 return FALSE;
242  
243 SMTPFlags.Val = 0x00;
244 SMTPFlags.bits.SMTPInUse = TRUE;
245 TransportState = TRANSPORT_BEGIN;
246 RXParserState = RX_BYTE_0;
247 SMTPState = SMTP_HOME;
248 memset((void*)&SMTPClient, 0x00, sizeof(SMTPClient));
249 SMTPClient.ServerPort = SMTP_PORT;
250  
251 return TRUE;
252 }
253  
254 /*****************************************************************************
255 Function:
256 WORD SMTPEndUsage(void)
257  
258 Summary:
259 Releases control of the SMTP client module.
260  
261 Description:
262 Call this function to release control of the SMTP client module once
263 an application is finished using it. This function releases the lock
264 obtained by SMTPBeginUsage, and frees the SMTP client to be used by
265 another application.
266  
267 Precondition:
268 SMTPBeginUsage returned TRUE on a previous call.
269  
270 Parameters:
271 None
272  
273 Return Values:
274 SMTP_SUCCESS - A message was successfully sent
275 SMTP_RESOLVE_ERROR - The SMTP server could not be resolved
276 SMTP_CONNECT_ERROR - The connection to the SMTP server failed or was
277 prematurely terminated
278 1-199 and 300-399 - The last SMTP server response code
279 ***************************************************************************/
280 WORD SMTPEndUsage(void)
281 {
282 if(!SMTPFlags.bits.SMTPInUse)
283 return 0xFFFF;
284  
285 // Release the DNS module, if in use
286 if(TransportState == TRANSPORT_NAME_RESOLVE)
287 DNSEndUsage();
288  
289 // Release the TCP socket, if in use
290 if(MySocket != INVALID_SOCKET)
291 {
292 TCPDisconnect(MySocket);
293 MySocket = INVALID_SOCKET;
294 }
295  
296 // Release the SMTP module
297 SMTPFlags.bits.SMTPInUse = FALSE;
298 TransportState = TRANSPORT_HOME;
299  
300 if(SMTPFlags.bits.SentSuccessfully)
301 {
302 return 0;
303 }
304 else
305 {
306 return ResponseCode;
307 }
308 }
309  
310 /*****************************************************************************
311 Function:
312 void SMTPTask(void)
313  
314 Summary:
315 Performs any pending SMTP client tasks
316  
317 Description:
318 This function handles periodic tasks associated with the SMTP client,
319 such as processing initial connections and command sequences.
320  
321 Precondition:
322 None
323  
324 Parameters:
325 None
326  
327 Returns:
328 None
329  
330 Remarks:
331 This function acts as a task (similar to one in an RTOS). It
332 performs its task in a co-operative manner, and the main application
333 must call this function repeatedly to ensure that all open or new
334 connections are served in a timely fashion.
335 ***************************************************************************/
336 void SMTPTask(void)
337 {
338 BYTE i;
339 WORD w;
340 BYTE vBase64Buffer[4];
341 static DWORD Timer;
342 static BYTE RXBuffer[4];
343 static ROM BYTE *ROMStrPtr, *ROMStrPtr2;
344 static BYTE *RAMStrPtr;
345 static WORD wAddressLength;
346  
347 switch(TransportState)
348 {
349 case TRANSPORT_HOME:
350 // SMTPBeginUsage() is the only function which will kick
351 // the state machine into the next state
352 break;
353  
354 case TRANSPORT_BEGIN:
355 // Wait for the user to program all the pointers and then
356 // call SMTPSendMail()
357 if(!SMTPFlags.bits.ReadyToStart)
358 break;
359  
360 // Obtain ownership of the DNS resolution module
361 if(!DNSBeginUsage())
362 break;
363  
364 // Obtain the IP address associated with the SMTP mail server
365 if(SMTPClient.Server.szRAM || SMTPClient.Server.szROM)
366 {
367 if(SMTPClient.ROMPointers.Server)
368 DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_A);
369 else
370 DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_A);
371 }
372 else
373 {
374 // If we don't have a mail server, try to send the mail
375 // directly to the destination SMTP server
376 if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To)
377 {
378 SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.To.szRAM, '@');
379 SMTPClient.ROMPointers.Server = 0;
380 }
381 else if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To)
382 {
383 SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.To.szROM, '@');
384 SMTPClient.ROMPointers.Server = 1;
385 }
386  
387 if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
388 {
389 if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC)
390 {
391 SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.CC.szRAM, '@');
392 SMTPClient.ROMPointers.Server = 0;
393 }
394 else if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC)
395 {
396 SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.CC.szROM, '@');
397 SMTPClient.ROMPointers.Server = 1;
398 }
399 }
400  
401 if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
402 {
403 if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC)
404 {
405 SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.BCC.szRAM, '@');
406 SMTPClient.ROMPointers.Server = 0;
407 }
408 else if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC)
409 {
410 SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.BCC.szROM, '@');
411 SMTPClient.ROMPointers.Server = 1;
412 }
413 }
414  
415 // See if we found a hostname anywhere which we could resolve
416 if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
417 {
418 DNSEndUsage();
419 ResponseCode = SMTP_RESOLVE_ERROR;
420 TransportState = TRANSPORT_HOME;
421 break;
422 }
423  
424 // Skip over the @ sign and resolve the host name
425 if(SMTPClient.ROMPointers.Server)
426 {
427 SMTPClient.Server.szROM++;
428 DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_MX);
429 }
430 else
431 {
432 SMTPClient.Server.szRAM++;
433 DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_MX);
434 }
435 }
436  
437 Timer = TickGet();
438 TransportState++;
439 break;
440  
441 case TRANSPORT_NAME_RESOLVE:
442 // Wait for the DNS server to return the requested IP address
443 if(!DNSIsResolved(&SMTPServer))
444 {
445 // Timeout after 6 seconds of unsuccessful DNS resolution
446 if(TickGet() - Timer > 6*TICK_SECOND)
447 {
448 ResponseCode = SMTP_RESOLVE_ERROR;
449 TransportState = TRANSPORT_HOME;
450 DNSEndUsage();
451 }
452 break;
453 }
454  
455 // Release the DNS module, we no longer need it
456 if(!DNSEndUsage())
457 {
458 // An invalid IP address was returned from the DNS
459 // server. Quit and fail permanantly if host is not valid.
460 ResponseCode = SMTP_RESOLVE_ERROR;
461 TransportState = TRANSPORT_HOME;
462 break;
463 }
464  
465 TransportState++;
466 // No need to break here
467  
468 case TRANSPORT_OBTAIN_SOCKET:
469 // Connect a TCP socket to the remote SMTP server
470 MySocket = TCPOpen(SMTPServer.Val, TCP_OPEN_IP_ADDRESS, SMTPClient.ServerPort, TCP_PURPOSE_DEFAULT);
471  
472 // Abort operation if no TCP sockets are available
473 // If this ever happens, add some more
474 // TCP_PURPOSE_DEFAULT sockets in TCPIPConfig.h
475 if(MySocket == INVALID_SOCKET)
476 break;
477  
478 TransportState++;
479 Timer = TickGet();
480 // No break; fall into TRANSPORT_SOCKET_OBTAINED
481  
482 #if defined(STACK_USE_SSL_CLIENT)
483 case TRANSPORT_SECURING_SOCKET:
484 if(!TCPIsConnected(MySocket))
485 {
486 // Don't stick around in the wrong state if the
487 // server was connected, but then disconnected us.
488 // Also time out if we can't establish the connection
489 // to the SMTP server
490 if((LONG)(TickGet()-Timer) > (LONG)(SMTP_SERVER_REPLY_TIMEOUT))
491 {
492 ResponseCode = SMTP_CONNECT_ERROR;
493 TransportState = TRANSPORT_CLOSE;
494 }
495  
496 break;
497 }
498 SMTPFlags.bits.ConnectedOnce = TRUE;
499  
500 // Start SSL if needed for this connection
501 if(SMTPClient.UseSSL && !TCPStartSSLClient(MySocket,NULL))
502 break;
503  
504 // Move on to main state
505 Timer = TickGet();
506 TransportState++;
507 break;
508 #endif
509  
510 case TRANSPORT_SOCKET_OBTAINED:
511 if(!TCPIsConnected(MySocket))
512 {
513 // Don't stick around in the wrong state if the
514 // server was connected, but then disconnected us.
515 // Also time out if we can't establish the connection
516 // to the SMTP server
517 if(SMTPFlags.bits.ConnectedOnce || ((LONG)(TickGet()-Timer) > (LONG)(SMTP_SERVER_REPLY_TIMEOUT)))
518 {
519 ResponseCode = SMTP_CONNECT_ERROR;
520 TransportState = TRANSPORT_CLOSE;
521 }
522  
523 break;
524 }
525 SMTPFlags.bits.ConnectedOnce = TRUE;
526  
527 #if defined(STACK_USE_SSL_CLIENT)
528 // Make sure the SSL handshake has completed
529 if(SMTPClient.UseSSL && TCPSSLIsHandshaking(MySocket))
530 break;
531 #endif
532  
533 // See if the server sent us anything
534 while(TCPIsGetReady(MySocket))
535 {
536 TCPGet(MySocket, &i);
537 switch(RXParserState)
538 {
539 case RX_BYTE_0:
540 case RX_BYTE_1:
541 case RX_BYTE_2:
542 RXBuffer[RXParserState] = i;
543 RXParserState++;
544 break;
545  
546 case RX_BYTE_3:
547 switch(i)
548 {
549 case ' ':
550 SMTPFlags.bits.RXSkipResponse = FALSE;
551 RXParserState++;
552 break;
553 case '-':
554 SMTPFlags.bits.RXSkipResponse = TRUE;
555 RXParserState++;
556 break;
557 case '\r':
558 RXParserState = RX_SEEK_LF;
559 break;
560 }
561 break;
562  
563 case RX_SEEK_CR:
564 if(i == '\r')
565 RXParserState++;
566 break;
567  
568 case RX_SEEK_LF:
569 // If we received the whole command
570 if(i == '\n')
571 {
572 RXParserState = RX_BYTE_0;
573  
574 if(!SMTPFlags.bits.RXSkipResponse)
575 {
576 // The server sent us a response code
577 // Null terminate the ASCII reponse code so we can convert it to an integer
578 RXBuffer[3] = 0;
579 ResponseCode = atoi((char*)RXBuffer);
580  
581 // Handle the response
582 switch(SMTPState)
583 {
584 case SMTP_HELO_ACK:
585 if(ResponseCode >= 200u && ResponseCode <= 299u)
586 {
587 if(SMTPClient.Username.szRAM || SMTPClient.Username.szROM)
588 SMTPState = SMTP_AUTH_LOGIN;
589 else
590 SMTPState = SMTP_MAILFROM;
591 }
592 else
593 SMTPState = SMTP_QUIT_INIT;
594 break;
595  
596  
597 case SMTP_AUTH_LOGIN_ACK:
598 case SMTP_AUTH_USERNAME_ACK:
599 if(ResponseCode == 334u)
600 SMTPState++;
601 else
602 SMTPState = SMTP_QUIT_INIT;
603 break;
604  
605 case SMTP_AUTH_PASSWORD_ACK:
606 if(ResponseCode == 235u)
607 SMTPState++;
608 else
609 SMTPState = SMTP_QUIT_INIT;
610 break;
611  
612 case SMTP_HOME:
613 case SMTP_MAILFROM_ACK:
614 case SMTP_RCPTTO_ACK:
615 case SMTP_RCPTTOCC_ACK:
616 case SMTP_RCPTTOBCC_ACK:
617 if(ResponseCode >= 200u && ResponseCode <= 299u)
618 SMTPState++;
619 else
620 SMTPState = SMTP_QUIT_INIT;
621 break;
622  
623 case SMTP_DATA_ACK:
624 if(ResponseCode == 354u)
625 SMTPState++;
626 else
627 SMTPState = SMTP_QUIT_INIT;
628 break;
629  
630 case SMTP_DATA_BODY_ACK:
631 if(ResponseCode >= 200u && ResponseCode <= 299u)
632 SMTPFlags.bits.SentSuccessfully = TRUE;
633  
634 SMTPState = SMTP_QUIT_INIT;
635 break;
636  
637 // Default case needed to supress compiler diagnostics
638 default:
639 break;
640 }
641 }
642 }
643 else if(i != '\r')
644 RXParserState--;
645  
646 break;
647 }
648 }
649  
650 // Generate new data in the TX buffer, as needed, if possible
651 if(TCPIsPutReady(MySocket) < 64u)
652 break;
653  
654 switch(SMTPState)
655 {
656 case SMTP_HELO:
657 if(SMTPClient.Username.szROM == NULL)
658 TCPPutROMString(MySocket, (ROM BYTE*)"HELO MCHPBOARD\r\n");
659 else
660 TCPPutROMString(MySocket, (ROM BYTE*)"EHLO MCHPBOARD\r\n");
661 TCPFlush(MySocket);
662 SMTPState++;
663 break;
664  
665 case SMTP_AUTH_LOGIN:
666 // Note: This state is only entered from SMTP_HELO_ACK if the application
667 // has specified a Username to use (either SMTPClient.Username.szROM or
668 // SMTPClient.Username.szRAM is non-NULL)
669 TCPPutROMString(MySocket, (ROM BYTE*)"AUTH LOGIN\r\n");
670 TCPFlush(MySocket);
671 SMTPState++;
672 break;
673  
674 case SMTP_AUTH_USERNAME:
675 // Base 64 encode and transmit the username.
676 if(SMTPClient.ROMPointers.Username)
677 {
678 ROMStrPtr = SMTPClient.Username.szROM;
679 w = strlenpgm((ROM char*)ROMStrPtr);
680 }
681 else
682 {
683 RAMStrPtr = SMTPClient.Username.szRAM;
684 w = strlen((char*)RAMStrPtr);
685 }
686  
687 while(w)
688 {
689 i = 0;
690 while((i < w) && (i < sizeof(vBase64Buffer)*3/4))
691 {
692 if(SMTPClient.ROMPointers.Username)
693 vBase64Buffer[i] = *ROMStrPtr++;
694 else
695 vBase64Buffer[i] = *RAMStrPtr++;
696 i++;
697 }
698 w -= i;
699 Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer));
700 TCPPutArray(MySocket, vBase64Buffer, sizeof(vBase64Buffer));
701 }
702 TCPPutROMString(MySocket, (ROM BYTE*)"\r\n");
703 TCPFlush(MySocket);
704 SMTPState++;
705 break;
706  
707 case SMTP_AUTH_PASSWORD:
708 // Base 64 encode and transmit the password
709 if(SMTPClient.ROMPointers.Password)
710 {
711 ROMStrPtr = SMTPClient.Password.szROM;
712 w = strlenpgm((ROM char*)ROMStrPtr);
713 }
714 else
715 {
716 RAMStrPtr = SMTPClient.Password.szRAM;
717 w = strlen((char*)RAMStrPtr);
718 }
719  
720 while(w)
721 {
722 i = 0;
723 while((i < w) && (i < sizeof(vBase64Buffer)*3/4))
724 {
725 if(SMTPClient.ROMPointers.Password)
726 vBase64Buffer[i] = *ROMStrPtr++;
727 else
728 vBase64Buffer[i] = *RAMStrPtr++;
729 i++;
730 }
731 w -= i;
732 Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer));
733 TCPPutArray(MySocket, vBase64Buffer, sizeof(vBase64Buffer));
734 }
735 TCPPutROMString(MySocket, (ROM BYTE*)"\r\n");
736 TCPFlush(MySocket);
737 SMTPState++;
738 break;
739  
740 case SMTP_MAILFROM:
741 // Send MAIL FROM header. Note that this is for the SMTP server validation,
742 // not what actually will be displayed in the recipients mail client as a
743 // return address.
744 TCPPutROMString(MySocket, (ROM BYTE*)"MAIL FROM:<");
745 if(SMTPClient.ROMPointers.From)
746 {
747 ROMStrPtr = FindROMEmailAddress(SMTPClient.From.szROM, &wAddressLength);
748 TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength);
749 }
750 else
751 {
752 RAMStrPtr = FindEmailAddress(SMTPClient.From.szRAM, &wAddressLength);
753 TCPPutArray(MySocket, RAMStrPtr, wAddressLength);
754 }
755 TCPPutROMString(MySocket, (ROM BYTE*)">\r\n");
756 TCPFlush(MySocket);
757 SMTPState++;
758 break;
759  
760 case SMTP_RCPTTO_INIT:
761 // See if there are any (To) recipients to process
762 if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To)
763 {
764 RAMStrPtr = FindEmailAddress(SMTPClient.To.szRAM, &wAddressLength);
765 if(wAddressLength)
766 {
767 SMTPState = SMTP_RCPTTO;
768 break;
769 }
770 }
771 if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To)
772 {
773 ROMStrPtr = FindROMEmailAddress(SMTPClient.To.szROM, &wAddressLength);
774 if(wAddressLength)
775 {
776 SMTPState = SMTP_RCPTTO;
777 break;
778 }
779 }
780  
781 SMTPState = SMTP_RCPTTOCC_INIT;
782 break;
783  
784 case SMTP_RCPTTO:
785 case SMTP_RCPTTOCC:
786 case SMTP_RCPTTOBCC:
787 TCPPutROMString(MySocket, (ROM BYTE*)"RCPT TO:<");
788 if( (SMTPClient.ROMPointers.To && (SMTPState == SMTP_RCPTTO)) ||
789 (SMTPClient.ROMPointers.CC && (SMTPState == SMTP_RCPTTOCC)) ||
790 (SMTPClient.ROMPointers.BCC && (SMTPState == SMTP_RCPTTOBCC)) )
791 TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength);
792 else
793 TCPPutArray(MySocket, RAMStrPtr, wAddressLength);
794 TCPPutROMString(MySocket, (ROM BYTE*)">\r\n");
795 TCPFlush(MySocket);
796 SMTPState++;
797 break;
798  
799 case SMTP_RCPTTO_ISDONE:
800 // See if we have any more (To) recipients to process
801 // If we do, we must roll back a couple of states
802 if(SMTPClient.ROMPointers.To)
803 ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
804 else
805 RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
806  
807 if(wAddressLength)
808 {
809 SMTPState = SMTP_RCPTTO;
810 break;
811 }
812  
813 // All done with To field
814 SMTPState++;
815 //No break
816  
817 case SMTP_RCPTTOCC_INIT:
818 // See if there are any Carbon Copy (CC) recipients to process
819 if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC)
820 {
821 RAMStrPtr = FindEmailAddress(SMTPClient.CC.szRAM, &wAddressLength);
822 if(wAddressLength)
823 {
824 SMTPState = SMTP_RCPTTOCC;
825 break;
826 }
827 }
828 if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC)
829 {
830 ROMStrPtr = FindROMEmailAddress(SMTPClient.CC.szROM, &wAddressLength);
831 if(wAddressLength)
832 {
833 SMTPState = SMTP_RCPTTOCC;
834 break;
835 }
836 }
837  
838 SMTPState = SMTP_RCPTTOBCC_INIT;
839 break;
840  
841 case SMTP_RCPTTOCC_ISDONE:
842 // See if we have any more Carbon Copy (CC) recipients to process
843 // If we do, we must roll back a couple of states
844 if(SMTPClient.ROMPointers.CC)
845 ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
846 else
847 RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
848  
849 if(wAddressLength)
850 {
851 SMTPState = SMTP_RCPTTOCC;
852 break;
853 }
854  
855 // All done with CC field
856 SMTPState++;
857 //No break
858  
859 case SMTP_RCPTTOBCC_INIT:
860 // See if there are any Blind Carbon Copy (BCC) recipients to process
861 if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC)
862 {
863 RAMStrPtr = FindEmailAddress(SMTPClient.BCC.szRAM, &wAddressLength);
864 if(wAddressLength)
865 {
866 SMTPState = SMTP_RCPTTOBCC;
867 break;
868 }
869 }
870 if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC)
871 {
872 ROMStrPtr = FindROMEmailAddress(SMTPClient.BCC.szROM, &wAddressLength);
873 if(wAddressLength)
874 {
875 SMTPState = SMTP_RCPTTOBCC;
876 break;
877 }
878 }
879  
880 // All done with BCC field
881 SMTPState = SMTP_DATA;
882 break;
883  
884 case SMTP_RCPTTOBCC_ISDONE:
885 // See if we have any more Blind Carbon Copy (CC) recipients to process
886 // If we do, we must roll back a couple of states
887 if(SMTPClient.ROMPointers.BCC)
888 ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
889 else
890 RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
891  
892 if(wAddressLength)
893 {
894 SMTPState = SMTP_RCPTTOBCC;
895 break;
896 }
897  
898 // All done with BCC field
899 SMTPState++;
900 //No break
901  
902 case SMTP_DATA:
903 TCPPutROMString(MySocket, (ROM BYTE*)"DATA\r\n");
904 SMTPState++;
905 PutHeadersState = PUTHEADERS_FROM_INIT;
906 TCPFlush(MySocket);
907 break;
908  
909 case SMTP_DATA_HEADER:
910 while((PutHeadersState != PUTHEADERS_DONE) && (TCPIsPutReady(MySocket) > 64u))
911 {
912 switch(PutHeadersState)
913 {
914 case PUTHEADERS_FROM_INIT:
915 if(SMTPClient.From.szRAM || SMTPClient.From.szROM)
916 {
917 PutHeadersState = PUTHEADERS_FROM;
918 TCPPutROMString(MySocket, (ROM BYTE*)"From: ");
919 }
920 else
921 {
922 PutHeadersState = PUTHEADERS_TO_INIT;
923 }
924 break;
925  
926 case PUTHEADERS_FROM:
927 if(SMTPClient.ROMPointers.From)
928 {
929 SMTPClient.From.szROM = TCPPutROMString(MySocket, SMTPClient.From.szROM);
930 if(*SMTPClient.From.szROM == 0u)
931 PutHeadersState = PUTHEADERS_TO_INIT;
932 }
933 else
934 {
935 SMTPClient.From.szRAM = TCPPutString(MySocket, SMTPClient.From.szRAM);
936 if(*SMTPClient.From.szRAM == 0u)
937 PutHeadersState = PUTHEADERS_TO_INIT;
938 }
939 break;
940  
941 case PUTHEADERS_TO_INIT:
942 if(SMTPClient.To.szRAM || SMTPClient.To.szROM)
943 {
944 PutHeadersState = PUTHEADERS_TO;
945 TCPPutROMString(MySocket, (ROM BYTE*)"\r\nTo: ");
946 }
947 else
948 {
949 PutHeadersState = PUTHEADERS_CC_INIT;
950 }
951 break;
952  
953 case PUTHEADERS_TO:
954 if(SMTPClient.ROMPointers.To)
955 {
956 SMTPClient.To.szROM = TCPPutROMString(MySocket, SMTPClient.To.szROM);
957 if(*SMTPClient.To.szROM == 0u)
958 PutHeadersState = PUTHEADERS_CC_INIT;
959 }
960 else
961 {
962 SMTPClient.To.szRAM = TCPPutString(MySocket, SMTPClient.To.szRAM);
963 if(*SMTPClient.To.szRAM == 0u)
964 PutHeadersState = PUTHEADERS_CC_INIT;
965 }
966 break;
967  
968 case PUTHEADERS_CC_INIT:
969 if(SMTPClient.CC.szRAM || SMTPClient.CC.szROM)
970 {
971 PutHeadersState = PUTHEADERS_CC;
972 TCPPutROMString(MySocket, (ROM BYTE*)"\r\nCC: ");
973 }
974 else
975 {
976 PutHeadersState = PUTHEADERS_SUBJECT_INIT;
977 }
978 break;
979  
980 case PUTHEADERS_CC:
981 if(SMTPClient.ROMPointers.CC)
982 {
983 SMTPClient.CC.szROM = TCPPutROMString(MySocket, SMTPClient.CC.szROM);
984 if(*SMTPClient.CC.szROM == 0u)
985 PutHeadersState = PUTHEADERS_SUBJECT_INIT;
986 }
987 else
988 {
989 SMTPClient.CC.szRAM = TCPPutString(MySocket, SMTPClient.CC.szRAM);
990 if(*SMTPClient.CC.szRAM == 0u)
991 PutHeadersState = PUTHEADERS_SUBJECT_INIT;
992 }
993 break;
994  
995 case PUTHEADERS_SUBJECT_INIT:
996 if(SMTPClient.Subject.szRAM || SMTPClient.Subject.szROM)
997 {
998 PutHeadersState = PUTHEADERS_SUBJECT;
999 TCPPutROMString(MySocket, (ROM BYTE*)"\r\nSubject: ");
1000 }
1001 else
1002 {
1003 PutHeadersState = PUTHEADERS_OTHER_INIT;
1004 }
1005 break;
1006  
1007 case PUTHEADERS_SUBJECT:
1008 if(SMTPClient.ROMPointers.Subject)
1009 {
1010 SMTPClient.Subject.szROM = TCPPutROMString(MySocket, SMTPClient.Subject.szROM);
1011 if(*SMTPClient.Subject.szROM == 0u)
1012 PutHeadersState = PUTHEADERS_OTHER_INIT;
1013 }
1014 else
1015 {
1016 SMTPClient.Subject.szRAM = TCPPutString(MySocket, SMTPClient.Subject.szRAM);
1017 if(*SMTPClient.Subject.szRAM == 0u)
1018 PutHeadersState = PUTHEADERS_OTHER_INIT;
1019 }
1020 break;
1021  
1022 case PUTHEADERS_OTHER_INIT:
1023 TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
1024 if(SMTPClient.OtherHeaders.szRAM || SMTPClient.OtherHeaders.szROM)
1025 {
1026 PutHeadersState = PUTHEADERS_OTHER;
1027 }
1028 else
1029 {
1030 TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
1031 PutHeadersState = PUTHEADERS_DONE;
1032 SMTPState++;
1033 }
1034 break;
1035  
1036 case PUTHEADERS_OTHER:
1037 if(SMTPClient.ROMPointers.OtherHeaders)
1038 {
1039 SMTPClient.OtherHeaders.szROM = TCPPutROMString(MySocket, SMTPClient.OtherHeaders.szROM);
1040 if(*SMTPClient.OtherHeaders.szROM == 0u)
1041 {
1042 TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
1043 PutHeadersState = PUTHEADERS_DONE;
1044 SMTPState++;
1045 }
1046 }
1047 else
1048 {
1049 SMTPClient.OtherHeaders.szRAM = TCPPutString(MySocket, SMTPClient.OtherHeaders.szRAM);
1050 if(*SMTPClient.OtherHeaders.szRAM == 0u)
1051 {
1052 TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
1053 PutHeadersState = PUTHEADERS_DONE;
1054 SMTPState++;
1055 }
1056 }
1057 break;
1058  
1059 // Default case needed to supress compiler diagnostics
1060 default:
1061 break;
1062 }
1063 }
1064 TCPFlush(MySocket);
1065 break;
1066  
1067 case SMTP_DATA_BODY_INIT:
1068 SMTPState++;
1069 RAMStrPtr = SMTPClient.Body.szRAM;
1070 ROMStrPtr2 = (ROM BYTE*)"\r\n.\r\n";
1071 CRPeriod.Pos = NULL;
1072 if(RAMStrPtr)
1073 CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n.");
1074 // No break here
1075  
1076 case SMTP_DATA_BODY:
1077 if(SMTPClient.Body.szRAM || SMTPClient.Body.szROM)
1078 {
1079 if(*ROMStrPtr2)
1080 {
1081 // Put the application data, doing the transparancy replacement of "\r\n." with "\r\n.."
1082 while(CRPeriod.Pos)
1083 {
1084 CRPeriod.Pos += 3;
1085 RAMStrPtr += TCPPutArray(MySocket, RAMStrPtr, CRPeriod.Pos-RAMStrPtr);
1086 if(RAMStrPtr == CRPeriod.Pos)
1087 {
1088 if(!TCPPut(MySocket, '.'))
1089 {
1090 CRPeriod.Pos -= 3;
1091 break;
1092 }
1093 }
1094 else
1095 {
1096 CRPeriod.Pos -= 3;
1097 break;
1098 }
1099 CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n.");
1100 }
1101  
1102 // If we get down here, either all replacements have been made or there is no remaining space in the TCP output buffer
1103 RAMStrPtr = TCPPutString(MySocket, RAMStrPtr);
1104 ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2);
1105 TCPFlush(MySocket);
1106 }
1107 }
1108 else
1109 {
1110 if(SMTPFlags.bits.ReadyToFinish)
1111 {
1112 if(*ROMStrPtr2)
1113 {
1114 ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2);
1115 TCPFlush(MySocket);
1116 }
1117  
1118 }
1119 }
1120  
1121 if(*ROMStrPtr2 == 0u)
1122 {
1123 SMTPState++;
1124 }
1125 break;
1126  
1127 case SMTP_QUIT_INIT:
1128 SMTPState++;
1129 ROMStrPtr = (ROM BYTE*)"QUIT\r\n";
1130 // No break here
1131  
1132 case SMTP_QUIT:
1133 if(*ROMStrPtr)
1134 {
1135 ROMStrPtr = TCPPutROMString(MySocket, ROMStrPtr);
1136 TCPFlush(MySocket);
1137 }
1138  
1139 if(*ROMStrPtr == 0u)
1140 {
1141 TransportState = TRANSPORT_CLOSE;
1142 }
1143 break;
1144  
1145 // Default case needed to supress compiler diagnostics
1146 default:
1147 break;
1148 }
1149 break;
1150  
1151 case TRANSPORT_CLOSE:
1152 // Close the socket so it can be used by other modules
1153 TCPDisconnect(MySocket);
1154 MySocket = INVALID_SOCKET;
1155  
1156 // Go back to doing nothing
1157 TransportState = TRANSPORT_HOME;
1158 break;
1159 }
1160 }
1161  
1162 /*****************************************************************************
1163 Function:
1164 void SMTPSendMail(void)
1165  
1166 Summary:
1167 Initializes the message sending process.
1168  
1169 Description:
1170 This function starts the state machine that performs the actual
1171 transmission of the message. Call this function after all the fields
1172 in SMTPClient have been set.
1173  
1174 Precondition:
1175 SMTPBeginUsage returned TRUE on a previous call.
1176  
1177 Parameters:
1178 None
1179  
1180 Returns:
1181 None
1182 ***************************************************************************/
1183 void SMTPSendMail(void)
1184 {
1185 SMTPFlags.bits.ReadyToStart = TRUE;
1186 }
1187  
1188 /*****************************************************************************
1189 Function:
1190 BOOL SMTPIsBusy(void)
1191  
1192 Summary:
1193 Determines if the SMTP client is busy.
1194  
1195 Description:
1196 Call this function to determine if the SMTP client is busy performing
1197 background tasks. This function should be called after any call to
1198 SMTPSendMail, SMTPPutDone to determine if the stack has finished
1199 performing its internal tasks. It should also be called prior to any
1200 call to SMTPIsPutReady to verify that the SMTP client has not
1201 prematurely disconnected. When this function returns FALSE, the next
1202 call should be to SMTPEndUsage to release the module and obtain the
1203 status code for the operation.
1204  
1205 Precondition:
1206 SMTPBeginUsage returned TRUE on a previous call.
1207  
1208 Parameters:
1209 None
1210  
1211 Return Values:
1212 TRUE - The SMTP Client is busy with internal tasks or sending an
1213 on-the-fly message.
1214 FALSE - The SMTP Client is terminated and is ready to be released.
1215 ***************************************************************************/
1216 BOOL SMTPIsBusy(void)
1217 {
1218 return TransportState != TRANSPORT_HOME;
1219 }
1220  
1221 /*****************************************************************************
1222 Function:
1223 WORD SMTPIsPutReady(void)
1224  
1225 Summary:
1226 Determines how much data can be written to the SMTP client.
1227  
1228 Description:
1229 Use this function to determine how much data can be written to the SMTP
1230 client when generating an on-the-fly message.
1231  
1232 Precondition:
1233 SMTPBeginUsage returned TRUE on a previous call, and an on-the-fly
1234 message is being generated. This requires that SMTPSendMail was called
1235 with SMTPClient.Body set to NULL.
1236  
1237 Parameters:
1238 None
1239  
1240 Returns:
1241 The number of free bytes the SMTP TX FIFO.
1242  
1243 Remarks:
1244 This function should only be called externally when the SMTP client is
1245 generating an on-the-fly message. (That is, SMTPSendMail was called
1246 with SMTPClient.Body set to NULL.)
1247 ***************************************************************************/
1248 WORD SMTPIsPutReady(void)
1249 {
1250 if(SMTPState != SMTP_DATA_BODY)
1251 return 0;
1252  
1253 return TCPIsPutReady(MySocket);
1254 }
1255  
1256 /*****************************************************************************
1257 Function:
1258 BOOL SMTPPut(BYTE c)
1259  
1260 Description:
1261 Writes a single byte to the SMTP client.
1262  
1263 Precondition:
1264 SMTPBeginUsage returned TRUE on a previous call.
1265  
1266 Parameters:
1267 c - The byte to be written
1268  
1269 Return Values:
1270 TRUE - The byte was successfully written
1271 FALSE - The byte was not written, most likely because the buffer was full
1272  
1273 Remarks:
1274 This function should only be called externally when the SMTP client is
1275 generating an on-the-fly message. (That is, SMTPSendMail was called
1276 with SMTPClient.Body set to NULL.)
1277 ***************************************************************************/
1278 BOOL SMTPPut(BYTE c)
1279 {
1280 if(CRPeriod.State == CR_PERIOD_NEED_INSERTION)
1281 {
1282 if(TCPPut(MySocket, '.'))
1283 CRPeriod.State = CR_PERIOD_SEEK_CR;
1284 else
1285 return FALSE;
1286 }
1287  
1288 switch(CRPeriod.State)
1289 {
1290 case CR_PERIOD_SEEK_CR:
1291 if(c == '\r')
1292 CRPeriod.State++;
1293 break;
1294  
1295 case CR_PERIOD_SEEK_LF:
1296 if(c == '\n')
1297 CRPeriod.State++;
1298 else if(c != '\r')
1299 CRPeriod.State--;
1300 break;
1301  
1302 case CR_PERIOD_SEEK_PERIOD:
1303 if(c == '.')
1304 CRPeriod.State++; // CR_PERIOD_NEED_INSERTION
1305 else if(c == '\r')
1306 CRPeriod.State--;
1307 else
1308 CRPeriod.State = CR_PERIOD_SEEK_CR;
1309 break;
1310  
1311 // Default case needed to supress compiler diagnostics
1312 // (CR_PERIOD_NEED_INSERTION state already handled above)
1313 default:
1314 break;
1315 }
1316  
1317 if(!TCPPut(MySocket, c))
1318 return FALSE;
1319  
1320 return TRUE;
1321 }
1322  
1323 /*****************************************************************************
1324 Function:
1325 WORD SMTPPutArray(BYTE* Data, WORD Len)
1326  
1327 Description:
1328 Writes a series of bytes to the SMTP client.
1329  
1330 Precondition:
1331 SMTPBeginUsage returned TRUE on a previous call.
1332  
1333 Parameters:
1334 Data - The data to be written
1335 Len - How many bytes should be written
1336  
1337 Returns:
1338 The number of bytes written. If less than Len, then the TX FIFO became
1339 full before all bytes could be written.
1340  
1341 Remarks:
1342 This function should only be called externally when the SMTP client is
1343 generating an on-the-fly message. (That is, SMTPSendMail was called
1344 with SMTPClient.Body set to NULL.)
1345  
1346 Internal:
1347 SMTPPut must be used instead of TCPPutArray because "\r\n." must be
1348 transparently replaced by "\r\n..".
1349 ***************************************************************************/
1350 WORD SMTPPutArray(BYTE* Data, WORD Len)
1351 {
1352 WORD result = 0;
1353  
1354 while(Len--)
1355 {
1356 if(SMTPPut(*Data++))
1357 {
1358 result++;
1359 }
1360 else
1361 {
1362 Data--;
1363 break;
1364 }
1365 }
1366  
1367 return result;
1368 }
1369  
1370 /*****************************************************************************
1371 Function:
1372 WORD SMTPPutROMArray(ROM BYTE* Data, WORD Len)
1373  
1374 Description:
1375 Writes a series of bytes from ROM to the SMTP client.
1376  
1377 Precondition:
1378 SMTPBeginUsage returned TRUE on a previous call.
1379  
1380 Parameters:
1381 Data - The data to be written
1382 Len - How many bytes should be written
1383  
1384 Returns:
1385 The number of bytes written. If less than Len, then the TX FIFO became
1386 full before all bytes could be written.
1387  
1388 Remarks:
1389 This function should only be called externally when the SMTP client is
1390 generating an on-the-fly message. (That is, SMTPSendMail was called
1391 with SMTPClient.Body set to NULL.)
1392  
1393 This function is aliased to SMTPPutArray on non-PIC18 platforms.
1394  
1395 Internal:
1396 SMTPPut must be used instead of TCPPutArray because "\r\n." must be
1397 transparently replaced by "\r\n..".
1398 ***************************************************************************/
1399 #if defined(__18CXX)
1400 WORD SMTPPutROMArray(ROM BYTE* Data, WORD Len)
1401 {
1402 WORD result = 0;
1403  
1404 while(Len--)
1405 {
1406 if(SMTPPut(*Data++))
1407 {
1408 result++;
1409 }
1410 else
1411 {
1412 Data--;
1413 break;
1414 }
1415 }
1416  
1417 return result;
1418 }
1419 #endif
1420  
1421 /*****************************************************************************
1422 Function:
1423 WORD SMTPPutString(BYTE* Data)
1424  
1425 Description:
1426 Writes a string to the SMTP client.
1427  
1428 Precondition:
1429 SMTPBeginUsage returned TRUE on a previous call.
1430  
1431 Parameters:
1432 Data - The data to be written
1433  
1434 Returns:
1435 The number of bytes written. If less than the length of Data, then the
1436 TX FIFO became full before all bytes could be written.
1437  
1438 Remarks:
1439 This function should only be called externally when the SMTP client is
1440 generating an on-the-fly message. (That is, SMTPSendMail was called
1441 with SMTPClient.Body set to NULL.)
1442  
1443 Internal:
1444 SMTPPut must be used instead of TCPPutString because "\r\n." must be
1445 transparently replaced by "\r\n..".
1446 ***************************************************************************/
1447 WORD SMTPPutString(BYTE* Data)
1448 {
1449 WORD result = 0;
1450  
1451 while(*Data)
1452 {
1453 if(SMTPPut(*Data++))
1454 {
1455 result++;
1456 }
1457 else
1458 {
1459 Data--;
1460 break;
1461 }
1462 }
1463  
1464 return result;
1465 }
1466  
1467 /*****************************************************************************
1468 Function:
1469 WORD SMTPPutROMString(ROM BYTE* Data)
1470  
1471 Description:
1472 Writes a string from ROM to the SMTP client.
1473  
1474 Precondition:
1475 SMTPBeginUsage returned TRUE on a previous call.
1476  
1477 Parameters:
1478 Data - The data to be written
1479  
1480 Returns:
1481 The number of bytes written. If less than the length of Data, then the
1482 TX FIFO became full before all bytes could be written.
1483  
1484 Remarks:
1485 This function should only be called externally when the SMTP client is
1486 generating an on-the-fly message. (That is, SMTPSendMail was called
1487 with SMTPClient.Body set to NULL.)
1488  
1489 This function is aliased to SMTPPutString on non-PIC18 platforms.
1490  
1491 Internal:
1492 SMTPPut must be used instead of TCPPutString because "\r\n." must be
1493 transparently replaced by "\r\n..".
1494 ***************************************************************************/
1495 #if defined(__18CXX)
1496 WORD SMTPPutROMString(ROM BYTE* Data)
1497 {
1498 WORD result = 0;
1499  
1500 while(*Data)
1501 {
1502 if(SMTPPut(*Data++))
1503 {
1504 result++;
1505 }
1506 else
1507 {
1508 Data--;
1509 break;
1510 }
1511 }
1512  
1513 return result;
1514 }
1515 #endif
1516  
1517 /*****************************************************************************
1518 Function:
1519 void SMTPFlush(void)
1520  
1521 Description:
1522 Flushes the SMTP socket and forces all data to be sent.
1523  
1524 Precondition:
1525 SMTPBeginUsage returned TRUE on a previous call.
1526  
1527 Parameters:
1528 None
1529  
1530 Returns:
1531 None
1532  
1533 Remarks:
1534 This function should only be called externally when the SMTP client is
1535 generating an on-the-fly message. (That is, SMTPSendMail was called
1536 with SMTPClient.Body set to NULL.)
1537 ***************************************************************************/
1538 void SMTPFlush(void)
1539 {
1540 TCPFlush(MySocket);
1541 }
1542  
1543 /*****************************************************************************
1544 Function:
1545 void SMTPPutDone(void)
1546  
1547 Description:
1548 Indicates that the on-the-fly message is complete.
1549  
1550 Precondition:
1551 SMTPBeginUsage returned TRUE on a previous call, and the SMTP client is
1552 generated an on-the-fly message. (That is, SMTPSendMail was called
1553 with SMTPClient.Body set to NULL.)
1554  
1555 Parameters:
1556 None
1557  
1558 Returns:
1559 None
1560 ***************************************************************************/
1561 void SMTPPutDone(void)
1562 {
1563 SMTPFlags.bits.ReadyToFinish = TRUE;
1564 }
1565  
1566 /*****************************************************************************
1567 Function:
1568 static BYTE *FindEmailAddress(BYTE *str, WORD *wLen)
1569  
1570 Summary:
1571 Searches a string for an e-mail address.
1572  
1573 Description:
1574 This function locates an e-mail address in a string. It is used
1575 internally by the SMTP client to parse out the actual address from
1576 the From and To strings so that the MAIL FROM and RCPT TO commands
1577 can be sent to the SMTP server.
1578  
1579 Precondition:
1580 SMTPBeginUsage returned TRUE on a previous call.
1581  
1582 Parameters:
1583 str - The string in which to search for an e-mail address
1584 wLen - the length of str
1585  
1586 Returns:
1587 A pointer to the e-mail address
1588 ***************************************************************************/
1589 static BYTE *FindEmailAddress(BYTE *str, WORD *wLen)
1590 {
1591 BYTE *lpStart;
1592 BYTE c;
1593 union
1594 {
1595 BYTE Val;
1596 struct
1597 {
1598 BYTE FoundOpenBracket : 1;
1599 BYTE FoundAt : 1;
1600 } bits;
1601 } ParseStates;
1602  
1603 lpStart = str;
1604 *wLen = 0x0000;
1605 ParseStates.Val = 0x00;
1606  
1607 while((c = *str++))
1608 {
1609 if(c == '<')
1610 {
1611 ParseStates.bits.FoundOpenBracket = 1;
1612 lpStart = str;
1613 *wLen = -1;
1614 }
1615 else if(c == '@')
1616 ParseStates.bits.FoundAt = 1;
1617  
1618  
1619 if( !ParseStates.bits.FoundOpenBracket &&
1620 !ParseStates.bits.FoundAt &&
1621 (c == ' ' || c == ','))
1622 {
1623 lpStart = str;
1624 continue;
1625 }
1626 else if(c == ',')
1627 break;
1628  
1629 if(ParseStates.bits.FoundOpenBracket && ParseStates.bits.FoundAt)
1630 {
1631 if(c == '>')
1632 break;
1633 }
1634  
1635 // Advance to next character
1636 *wLen += 1;
1637 }
1638  
1639 if(!ParseStates.bits.FoundAt)
1640 *wLen = 0;
1641  
1642 return lpStart;
1643 }
1644  
1645 /*****************************************************************************
1646 Function:
1647 static ROM BYTE *FindROMEmailAddress(ROM BYTE *str, WORD *wLen)
1648  
1649 Summary:
1650 Searches a ROM string for an e-mail address.
1651  
1652 Description:
1653 This function locates an e-mail address in a string. It is used
1654 internally by the SMTP client to parse out the actual address from
1655 the From and To strings so that the MAIL FROM and RCPT TO commands
1656 can be sent to the SMTP server.
1657  
1658 Precondition:
1659 SMTPBeginUsage returned TRUE on a previous call.
1660  
1661 Parameters:
1662 str - The ROM string in which to search for an e-mail address
1663 wLen - the length of str
1664  
1665 Returns:
1666 A pointer to the e-mail address
1667 ***************************************************************************/
1668 static ROM BYTE *FindROMEmailAddress(ROM BYTE *str, WORD *wLen)
1669 {
1670 ROM BYTE *lpStart;
1671 BYTE c;
1672 union
1673 {
1674 BYTE Val;
1675 struct
1676 {
1677 BYTE FoundOpenBracket : 1;
1678 BYTE FoundAt : 1;
1679 } bits;
1680 } ParseStates;
1681  
1682 lpStart = str;
1683 *wLen = 0x0000;
1684 ParseStates.Val = 0x00;
1685  
1686 while((c = *str++))
1687 {
1688 if(c == '<')
1689 {
1690 ParseStates.bits.FoundOpenBracket = 1;
1691 lpStart = str;
1692 *wLen = -1;
1693 }
1694 else if(c == '@')
1695 ParseStates.bits.FoundAt = 1;
1696  
1697  
1698 if( !ParseStates.bits.FoundOpenBracket &&
1699 !ParseStates.bits.FoundAt &&
1700 (c == ' ' || c == ','))
1701 {
1702 lpStart = str;
1703 continue;
1704 }
1705 else if(c == ',')
1706 break;
1707  
1708 if(ParseStates.bits.FoundOpenBracket && ParseStates.bits.FoundAt)
1709 {
1710 if(c == '>')
1711 break;
1712 }
1713  
1714 // Advance to next character
1715 *wLen += 1;
1716 }
1717  
1718 if(!ParseStates.bits.FoundAt)
1719 *wLen = 0;
1720  
1721 return lpStart;
1722 }
1723  
1724 #endif //#if defined(STACK_USE_SMTP_CLIENT)
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3