/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/SMTP.c
ViewVC logotype

Annotation of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/SMTP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 31049 byte(s)
added the TCP/IP stack, source code.
1 hedin 15 /*********************************************************************
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, STACK_CLIENT_MODE
11     * Processor: PIC18, PIC24F, PIC24H, dsPIC30, dsPIC33F
12     * Complier: Microchip C18 v3.02 or higher
13     * Microchip C30 v2.05 or higher
14     * Company: Microchip Technology, Inc.
15     *
16     * Software License Agreement
17     *
18     * Copyright © 2002-2007 Microchip Technology Inc. All rights
19     * reserved.
20     *
21     * Microchip licenses to you the right to use, modify, copy, and
22     * distribute:
23     * (i) the Software when embedded on a Microchip microcontroller or
24     * digital signal controller product (“Device”) which is
25     * integrated into Licensee’s product; or
26     * (ii) ONLY the Software driver source files ENC28J60.c and
27     * ENC28J60.h ported to a non-Microchip device used in
28     * conjunction with a Microchip ethernet controller for the
29     * sole purpose of interfacing with the ethernet controller.
30     *
31     * You should refer to the license agreement accompanying this
32     * Software for additional information regarding your rights and
33     * obligations.
34     *
35     * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
36     * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
37     * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
38     * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
39     * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
40     * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
41     * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
42     * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
43     * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
44     * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
45     * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
46     *
47     *
48     * Author Date Comment
49     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50     * Howard Schlunder 3/03/06 Original
51     * Howard Schlunder 11/2/06 Vastly improved for release
52     ********************************************************************/
53     #define __SMTP_C
54    
55     #include "TCPIP Stack/TCPIP.h"
56    
57     #if defined(STACK_USE_SMTP_CLIENT)
58    
59    
60     #define SMTP_PORT 25
61    
62     // Public variables
63     // Public string pointers controlling the mail message.
64     // Application must set these after calling SMTPBeginUsage().
65     // Unneeded fields should be set to NULL.
66     SMTP_POINTERS SMTPClient;
67    
68     // Internal variables
69     static NODE_INFO SMTPServer;
70     static TCP_SOCKET MySocket = INVALID_SOCKET;
71     static TICK LastPutTime;
72     static union
73     {
74     BYTE *Pos;
75     enum
76     {
77     CR_PERIOD_SEEK_CR = 0,
78     CR_PERIOD_SEEK_LF,
79     CR_PERIOD_SEEK_PERIOD,
80     CR_PERIOD_NEED_INSERTION
81     } State;
82     } CRPeriod;
83     static enum _TransportState
84     {
85     TRANSPORT_HOME = 0,
86     TRANSPORT_BEGIN,
87     TRANSPORT_NAME_RESOLVE,
88     TRANSPORT_ARP_START_RESOLVE,
89     TRANSPORT_ARP_IN_PROGRESS,
90     TRANSPORT_ARP_RESOLVED,
91     TRANSPORT_SOCKET_OBTAINED,
92     TRANSPORT_CLOSE
93     } TransportState = TRANSPORT_HOME;
94     static enum _SMTPState
95     {
96     SMTP_HOME = 0,
97     SMTP_HELO,
98     SMTP_HELO_ACK,
99     SMTP_MAILFROM,
100     SMTP_MAILFROM_ACK,
101     SMTP_RCPTTO_INIT,
102     SMTP_RCPTTO,
103     SMTP_RCPTTO_ACK,
104     SMTP_RCPTTO_ISDONE,
105     SMTP_RCPTTOCC_INIT,
106     SMTP_RCPTTOCC,
107     SMTP_RCPTTOCC_ACK,
108     SMTP_RCPTTOCC_ISDONE,
109     SMTP_RCPTTOBCC_INIT,
110     SMTP_RCPTTOBCC,
111     SMTP_RCPTTOBCC_ACK,
112     SMTP_RCPTTOBCC_ISDONE,
113     SMTP_DATA,
114     SMTP_DATA_ACK,
115     SMTP_DATA_HEADER,
116     SMTP_DATA_BODY_INIT,
117     SMTP_DATA_BODY,
118     SMTP_DATA_BODY_ACK,
119     SMTP_QUIT_INIT,
120     SMTP_QUIT
121     } SMTPState;
122     static enum _PutHeadersState
123     {
124     PUTHEADERS_FROM_INIT = 0,
125     PUTHEADERS_FROM,
126     PUTHEADERS_TO_INIT,
127     PUTHEADERS_TO,
128     PUTHEADERS_CC_INIT,
129     PUTHEADERS_CC,
130     PUTHEADERS_SUBJECT_INIT,
131     PUTHEADERS_SUBJECT,
132     PUTHEADERS_OTHER_INIT,
133     PUTHEADERS_OTHER,
134     PUTHEADERS_DONE
135     } PutHeadersState;
136     static enum _RXParserState
137     {
138     RX_BYTE_0 = 0,
139     RX_BYTE_1,
140     RX_BYTE_2,
141     RX_BYTE_3,
142     RX_SEEK_CR,
143     RX_SEEK_LF
144     } RXParserState;
145     static union _SMTPFlags
146     {
147     BYTE Val;
148     struct
149     {
150     unsigned char RXSkipResponse:1;
151     unsigned char SMTPInUse:1;
152     unsigned char SentSuccessfully:1;
153     unsigned char ReadyToStart:1;
154     unsigned char ReadyToFinish:1;
155     unsigned char ConnectedOnce:1;
156     unsigned char filler:2;
157     } bits;
158     } SMTPFlags = {0x00};
159     static WORD ResponseCode;
160    
161     // Internal functions
162     static BYTE *FindEmailAddress(BYTE *str, WORD *wLen);
163     static ROM BYTE *FindROMEmailAddress(ROM BYTE *str, WORD *wLen);
164    
165    
166     /*********************************************************************
167     * Function: BOOL SMTPBeginUsage(void)
168     *
169     * PreCondition: Stack is initialized()
170     *
171     * Input: None
172     *
173     * Output: TRUE: If no SMTP operations are in progress and this application has successfully taken ownership of the SMTP module
174     * 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).
175     *
176     * Side Effects: None
177     *
178     * 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.
179     *
180     * Note: None
181     ********************************************************************/
182     BOOL SMTPBeginUsage(void)
183     {
184     static BYTE NullString = '\0';
185    
186     if(SMTPFlags.bits.SMTPInUse)
187     return FALSE;
188    
189     SMTPFlags.Val = 0x00;
190     SMTPFlags.bits.SMTPInUse = TRUE;
191     TransportState = TRANSPORT_BEGIN;
192     RXParserState = RX_BYTE_0;
193     SMTPState = SMTP_HOME;
194     memset((void*)&SMTPClient, 0x00, sizeof(SMTPClient));
195    
196     return TRUE;
197     }
198    
199    
200     /*********************************************************************
201     * Function: void SMTPEndUsage(void)
202     *
203     * PreCondition: SMTPBeginUsage() returned TRUE on a previous call.
204     *
205     * Input: None
206     *
207     * Output: SMTP_SUCCESS (0x0000): on success
208     * SMTP_RESOLVE_ERROR (0x8000): if unable to resolve SMTP server
209     * SMTP_CONNECT_ERROR (0x8001): if unable to connect to SMTP server or connection lost
210     * 1-199 and 300-999: last SMTP server response code
211     *
212     * Side Effects: None
213     *
214     * Overview: Releases ownership of the SMTP module caused by a
215     * previous call to SMTPBeginUsage()
216     *
217     * Note: None
218     ********************************************************************/
219     WORD SMTPEndUsage(void)
220     {
221     if(!SMTPFlags.bits.SMTPInUse)
222     return FALSE;
223    
224     // Release the DNS module, if in use
225     if(TransportState == TRANSPORT_NAME_RESOLVE)
226     DNSEndUsage();
227    
228     // Release the TCP socket, if in use
229     if(MySocket != INVALID_SOCKET)
230     {
231     TCPDisconnect(MySocket);
232     MySocket = INVALID_SOCKET;
233     }
234    
235     // Release the SMTP module
236     SMTPFlags.bits.SMTPInUse = FALSE;
237     TransportState = TRANSPORT_HOME;
238    
239     if(SMTPFlags.bits.SentSuccessfully)
240     {
241     return 0;
242     }
243     else
244     {
245     return ResponseCode;
246     }
247     }
248    
249     /*********************************************************************
250     * Function: void SMTPTask(void)
251     *
252     * PreCondition: Stack is initialized()
253     *
254     * Input: None
255     *
256     * Output: None
257     *
258     * Side Effects: Uses ARP module
259     *
260     * Overview: None
261     *
262     * Note: This is a work is in progress
263     ********************************************************************/
264     void SMTPTask(void)
265     {
266     BYTE c;
267     static TICK Timer;
268     static BYTE RXBuffer[4];
269     static ROM BYTE *ROMStrPtr, *ROMStrPtr2;
270     static BYTE *RAMStrPtr;
271     static WORD wAddressLength;
272    
273     switch(TransportState)
274     {
275     case TRANSPORT_HOME:
276     // SMTPBeginUsage() is the only function which will kick
277     // the state machine into the next state
278     break;
279    
280     case TRANSPORT_BEGIN:
281     // Wait for the user to program all the pointers and then
282     // call SMTPSendMail()
283     if(!SMTPFlags.bits.ReadyToStart)
284     break;
285    
286     // Obtain ownership of the DNS resolution module
287     if(!DNSBeginUsage())
288     break;
289    
290     // Obtain the IP address associated with the SMTP mail server
291     if(SMTPClient.Server.szRAM || SMTPClient.Server.szROM)
292     {
293     if(SMTPClient.ROMPointers.Server)
294     DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_A);
295     else
296     DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_A);
297     }
298     else
299     {
300     // If we don't have a mail server, try to send the mail
301     // directly to the destination SMTP server
302     if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To)
303     {
304     SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.To.szRAM, '@');
305     SMTPClient.ROMPointers.Server = 0;
306     }
307     else if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To)
308     {
309     SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.To.szROM, '@');
310     SMTPClient.ROMPointers.Server = 1;
311     }
312    
313     if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
314     {
315     if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC)
316     {
317     SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.CC.szRAM, '@');
318     SMTPClient.ROMPointers.Server = 0;
319     }
320     else if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC)
321     {
322     SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.CC.szROM, '@');
323     SMTPClient.ROMPointers.Server = 1;
324     }
325     }
326    
327     if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
328     {
329     if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC)
330     {
331     SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.BCC.szRAM, '@');
332     SMTPClient.ROMPointers.Server = 0;
333     }
334     else if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC)
335     {
336     SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.BCC.szROM, '@');
337     SMTPClient.ROMPointers.Server = 1;
338     }
339     }
340    
341     // See if we found a hostname anywhere which we could resolve
342     if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
343     {
344     DNSEndUsage();
345     TransportState = TRANSPORT_HOME;
346     break;
347     }
348    
349     // Skip over the @ sign and resolve the host name
350     if(SMTPClient.ROMPointers.Server)
351     {
352     SMTPClient.Server.szROM++;
353     DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_MX);
354     }
355     else
356     {
357     SMTPClient.Server.szRAM++;
358     DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_MX);
359     }
360     }
361    
362     TransportState++;
363     break;
364    
365     case TRANSPORT_NAME_RESOLVE:
366     // Wait for the DNS server to return the requested IP address
367     if(!DNSIsResolved(&SMTPServer.IPAddr))
368     break;
369    
370     // Release the DNS module, we no longer need it
371     if(!DNSEndUsage())
372     {
373     // An invalid IP address was returned from the DNS
374     // server. Quit and fail permanantly if host is not valid.
375     ResponseCode = SMTP_RESOLVE_ERROR;
376     TransportState = TRANSPORT_HOME;
377     break;
378     }
379    
380     TransportState++;
381     // No need to break here
382    
383     case TRANSPORT_ARP_START_RESOLVE:
384     // Obtain the MAC address associated with the server's IP address (either direct MAC address on same subnet, or the MAC address of the Gateway machine)
385     ARPResolve(&SMTPServer.IPAddr);
386     Timer = TickGet();
387     TransportState++;
388     break;
389    
390     case TRANSPORT_ARP_IN_PROGRESS:
391     // Check to see if the MAC address has been resovlved
392     if(!ARPIsResolved(&SMTPServer.IPAddr, &SMTPServer.MACAddr))
393     {
394     // Time out if too much time is spent in this state
395     if(TickGet()-Timer > 2*TICK_SECOND)
396     {
397     ResponseCode = SMTP_RESOLVE_ERROR;
398     // Retry ARP resolution
399     TransportState = TRANSPORT_HOME;
400     }
401     break;
402     }
403    
404     TransportState++;
405     Timer = TickGet();
406     // No break; fall into SM_ARP_RESOLVED
407    
408     case TRANSPORT_ARP_RESOLVED:
409     // Connect a TCP socket to the remote SMTP server
410     MySocket = TCPConnect(&SMTPServer, SMTP_PORT);
411    
412     // Abort operation if no TCP sockets are available
413     // If this ever happens, incrementing MAX_TCP_SOCKETS in
414     // TCPIPConfig. may help (at the expense of more global memory
415     // resources).
416     if(MySocket == INVALID_SOCKET)
417     break;
418    
419     TransportState++;
420     Timer = TickGet();
421     // No break; fall into SM_SOCKET_OBTAINED
422    
423     case TRANSPORT_SOCKET_OBTAINED:
424     if(!TCPIsConnected(MySocket))
425     {
426     // Don't stick around in the wrong state if the
427     // server was connected, but then disconnected us.
428     // Also time out if we can't establish the connection
429     // to the SMTP server
430     if(SMTPFlags.bits.ConnectedOnce || ((LONG)(TickGet()-Timer) > (LONG)(8*TICK_SECOND)))
431     {
432     ResponseCode = SMTP_CONNECT_ERROR;
433     TransportState = TRANSPORT_CLOSE;
434     }
435    
436     break;
437     }
438     SMTPFlags.bits.ConnectedOnce = TRUE;
439    
440     // See if the server sent us anything
441     while(TCPIsGetReady(MySocket))
442     {
443     TCPGet(MySocket, &c);
444     switch(RXParserState)
445     {
446     case RX_BYTE_0:
447     case RX_BYTE_1:
448     case RX_BYTE_2:
449     RXBuffer[RXParserState] = c;
450     RXParserState++;
451     break;
452    
453     case RX_BYTE_3:
454     switch(c)
455     {
456     case ' ':
457     SMTPFlags.bits.RXSkipResponse = FALSE;
458     RXParserState++;
459     break;
460     case '-':
461     SMTPFlags.bits.RXSkipResponse = TRUE;
462     RXParserState++;
463     break;
464     case '\r':
465     RXParserState = RX_SEEK_LF;
466     break;
467     }
468     break;
469    
470     case RX_SEEK_CR:
471     if(c == '\r')
472     RXParserState++;
473     break;
474    
475     case RX_SEEK_LF:
476     // If we received the whole command
477     if(c == '\n')
478     {
479     RXParserState = RX_BYTE_0;
480    
481     if(!SMTPFlags.bits.RXSkipResponse)
482     {
483     // The server sent us a response code
484     // Null terminate the ASCII reponse code so we can convert it to an integer
485     RXBuffer[3] = 0;
486     ResponseCode = atoi((char*)RXBuffer);
487    
488     // Handle the response
489     switch(SMTPState)
490     {
491     case SMTP_HOME:
492     case SMTP_HELO_ACK:
493     case SMTP_MAILFROM_ACK:
494     case SMTP_RCPTTO_ACK:
495     case SMTP_RCPTTOCC_ACK:
496     case SMTP_RCPTTOBCC_ACK:
497     if(ResponseCode >= 200u && ResponseCode <= 299u)
498     SMTPState++;
499     else
500     SMTPState = SMTP_QUIT_INIT;
501     break;
502    
503     case SMTP_DATA_ACK:
504     if(ResponseCode == 354u)
505     SMTPState++;
506     else
507     SMTPState = SMTP_QUIT_INIT;
508     break;
509    
510     case SMTP_DATA_BODY_ACK:
511     if(ResponseCode >= 200u && ResponseCode <= 299u)
512     SMTPFlags.bits.SentSuccessfully = TRUE;
513    
514     SMTPState = SMTP_QUIT_INIT;
515     break;
516     }
517     }
518     }
519     else if(c != '\r')
520     RXParserState--;
521    
522     break;
523     }
524     }
525    
526     // Generate new data in the TX buffer, as needed, if possible
527     if(TCPIsPutReady(MySocket) < 64u)
528     break;
529    
530     switch(SMTPState)
531     {
532     case SMTP_HELO:
533     TCPPutROMString(MySocket, (ROM BYTE*)"HELO MCHPBOARD\r\n");
534     TCPFlush(MySocket);
535     SMTPState++;
536     break;
537    
538     case SMTP_MAILFROM:
539     TCPPutROMString(MySocket, (ROM BYTE*)"MAIL FROM:<");
540     if(SMTPClient.ROMPointers.From)
541     {
542     ROMStrPtr = FindROMEmailAddress(SMTPClient.From.szROM, &wAddressLength);
543     TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength);
544     }
545     else
546     {
547     RAMStrPtr = FindEmailAddress(SMTPClient.From.szRAM, &wAddressLength);
548     TCPPutArray(MySocket, RAMStrPtr, wAddressLength);
549     }
550     TCPPutROMString(MySocket, (ROM BYTE*)">\r\n");
551     TCPFlush(MySocket);
552     SMTPState++;
553     break;
554    
555     case SMTP_RCPTTO_INIT:
556     // See if there are any (To) recipients to process
557     if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To)
558     {
559     RAMStrPtr = FindEmailAddress(SMTPClient.To.szRAM, &wAddressLength);
560     if(wAddressLength)
561     {
562     SMTPState = SMTP_RCPTTO;
563     break;
564     }
565     }
566     if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To)
567     {
568     ROMStrPtr = FindROMEmailAddress(SMTPClient.To.szROM, &wAddressLength);
569     if(wAddressLength)
570     {
571     SMTPState = SMTP_RCPTTO;
572     break;
573     }
574     }
575    
576     SMTPState = SMTP_RCPTTOCC_INIT;
577     break;
578    
579     case SMTP_RCPTTO:
580     case SMTP_RCPTTOCC:
581     case SMTP_RCPTTOBCC:
582     TCPPutROMString(MySocket, (ROM BYTE*)"RCPT TO:<");
583     if(SMTPClient.ROMPointers.To)
584     TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength);
585     else
586     TCPPutArray(MySocket, RAMStrPtr, wAddressLength);
587     TCPPutROMString(MySocket, (ROM BYTE*)">\r\n");
588     TCPFlush(MySocket);
589     SMTPState++;
590     break;
591    
592     case SMTP_RCPTTO_ISDONE:
593     // See if we have any more (To) recipients to process
594     // If we do, we must roll back a couple of states
595     if(SMTPClient.ROMPointers.To)
596     ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
597     else
598     RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
599    
600     if(wAddressLength)
601     {
602     SMTPState = SMTP_RCPTTO;
603     break;
604     }
605    
606     // All done with To field
607     SMTPState++;
608     //No break
609    
610     case SMTP_RCPTTOCC_INIT:
611     // See if there are any Carbon Copy (CC) recipients to process
612     if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC)
613     {
614     RAMStrPtr = FindEmailAddress(SMTPClient.CC.szRAM, &wAddressLength);
615     if(wAddressLength)
616     {
617     SMTPState = SMTP_RCPTTOCC;
618     break;
619     }
620     }
621     if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC)
622     {
623     ROMStrPtr = FindROMEmailAddress(SMTPClient.CC.szROM, &wAddressLength);
624     if(wAddressLength)
625     {
626     SMTPState = SMTP_RCPTTOCC;
627     break;
628     }
629     }
630    
631     SMTPState = SMTP_RCPTTOBCC_INIT;
632     break;
633    
634     case SMTP_RCPTTOCC_ISDONE:
635     // See if we have any more Carbon Copy (CC) recipients to process
636     // If we do, we must roll back a couple of states
637     if(SMTPClient.ROMPointers.CC)
638     ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
639     else
640     RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
641    
642     if(wAddressLength)
643     {
644     SMTPState = SMTP_RCPTTOCC;
645     break;
646     }
647    
648     // All done with CC field
649     SMTPState++;
650     //No break
651    
652     case SMTP_RCPTTOBCC_INIT:
653     // See if there are any Blind Carbon Copy (BCC) recipients to process
654     if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC)
655     {
656     RAMStrPtr = FindEmailAddress(SMTPClient.BCC.szRAM, &wAddressLength);
657     if(wAddressLength)
658     {
659     SMTPState = SMTP_RCPTTOBCC;
660     break;
661     }
662     }
663     if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC)
664     {
665     ROMStrPtr = FindROMEmailAddress(SMTPClient.BCC.szROM, &wAddressLength);
666     if(wAddressLength)
667     {
668     SMTPState = SMTP_RCPTTOBCC;
669     break;
670     }
671     }
672    
673     // All done with BCC field
674     SMTPState = SMTP_DATA;
675     break;
676    
677     case SMTP_RCPTTOBCC_ISDONE:
678     // See if we have any more Blind Carbon Copy (CC) recipients to process
679     // If we do, we must roll back a couple of states
680     if(SMTPClient.ROMPointers.BCC)
681     ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
682     else
683     RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
684    
685     if(wAddressLength)
686     {
687     SMTPState = SMTP_RCPTTOBCC;
688     break;
689     }
690    
691     // All done with BCC field
692     SMTPState++;
693     //No break
694    
695     case SMTP_DATA:
696     TCPPutROMString(MySocket, (ROM BYTE*)"DATA\r\n");
697     SMTPState++;
698     PutHeadersState = PUTHEADERS_FROM_INIT;
699     TCPFlush(MySocket);
700     break;
701    
702     case SMTP_DATA_HEADER:
703     while((PutHeadersState != PUTHEADERS_DONE) && (TCPIsPutReady(MySocket) > 64u))
704     {
705     switch(PutHeadersState)
706     {
707     case PUTHEADERS_FROM_INIT:
708     if(SMTPClient.From.szRAM || SMTPClient.From.szROM)
709     {
710     PutHeadersState = PUTHEADERS_FROM;
711     TCPPutROMString(MySocket, (ROM BYTE*)"From: ");
712     }
713     else
714     {
715     PutHeadersState = PUTHEADERS_TO_INIT;
716     }
717     break;
718    
719     case PUTHEADERS_FROM:
720     if(SMTPClient.ROMPointers.From)
721     {
722     SMTPClient.From.szROM = TCPPutROMString(MySocket, SMTPClient.From.szROM);
723     if(*SMTPClient.From.szROM == 0)
724     PutHeadersState = PUTHEADERS_TO_INIT;
725     }
726     else
727     {
728     SMTPClient.From.szRAM = TCPPutString(MySocket, SMTPClient.From.szRAM);
729     if(*SMTPClient.From.szRAM == 0)
730     PutHeadersState = PUTHEADERS_TO_INIT;
731     }
732     break;
733    
734     case PUTHEADERS_TO_INIT:
735     if(SMTPClient.To.szRAM || SMTPClient.To.szROM)
736     {
737     PutHeadersState = PUTHEADERS_TO;
738     TCPPutROMString(MySocket, (ROM BYTE*)"\r\nTo: ");
739     }
740     else
741     {
742     PutHeadersState = PUTHEADERS_CC_INIT;
743     }
744     break;
745    
746     case PUTHEADERS_TO:
747     if(SMTPClient.ROMPointers.To)
748     {
749     SMTPClient.To.szROM = TCPPutROMString(MySocket, SMTPClient.To.szROM);
750     if(*SMTPClient.To.szROM == 0)
751     PutHeadersState = PUTHEADERS_CC_INIT;
752     }
753     else
754     {
755     SMTPClient.To.szRAM = TCPPutString(MySocket, SMTPClient.To.szRAM);
756     if(*SMTPClient.To.szRAM == 0)
757     PutHeadersState = PUTHEADERS_CC_INIT;
758     }
759     break;
760    
761     case PUTHEADERS_CC_INIT:
762     if(SMTPClient.CC.szRAM || SMTPClient.CC.szROM)
763     {
764     PutHeadersState = PUTHEADERS_CC;
765     TCPPutROMString(MySocket, (ROM BYTE*)"\r\nCC: ");
766     }
767     else
768     {
769     PutHeadersState = PUTHEADERS_SUBJECT_INIT;
770     }
771     break;
772    
773     case PUTHEADERS_CC:
774     if(SMTPClient.ROMPointers.CC)
775     {
776     SMTPClient.CC.szROM = TCPPutROMString(MySocket, SMTPClient.CC.szROM);
777     if(*SMTPClient.CC.szROM == 0)
778     PutHeadersState = PUTHEADERS_SUBJECT_INIT;
779     }
780     else
781     {
782     SMTPClient.CC.szRAM = TCPPutString(MySocket, SMTPClient.CC.szRAM);
783     if(*SMTPClient.CC.szRAM == 0)
784     PutHeadersState = PUTHEADERS_SUBJECT_INIT;
785     }
786     break;
787    
788     case PUTHEADERS_SUBJECT_INIT:
789     if(SMTPClient.Subject.szRAM || SMTPClient.Subject.szROM)
790     {
791     PutHeadersState = PUTHEADERS_SUBJECT;
792     TCPPutROMString(MySocket, (ROM BYTE*)"\r\nSubject: ");
793     }
794     else
795     {
796     PutHeadersState = PUTHEADERS_OTHER_INIT;
797     }
798     break;
799    
800     case PUTHEADERS_SUBJECT:
801     if(SMTPClient.ROMPointers.Subject)
802     {
803     SMTPClient.Subject.szROM = TCPPutROMString(MySocket, SMTPClient.Subject.szROM);
804     if(*SMTPClient.Subject.szROM == 0)
805     PutHeadersState = PUTHEADERS_OTHER_INIT;
806     }
807     else
808     {
809     SMTPClient.Subject.szRAM = TCPPutString(MySocket, SMTPClient.Subject.szRAM);
810     if(*SMTPClient.Subject.szRAM == 0)
811     PutHeadersState = PUTHEADERS_OTHER_INIT;
812     }
813     break;
814    
815     case PUTHEADERS_OTHER_INIT:
816     TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
817     if(SMTPClient.OtherHeaders.szRAM || SMTPClient.OtherHeaders.szROM)
818     {
819     PutHeadersState = PUTHEADERS_OTHER;
820     }
821     else
822     {
823     TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
824     PutHeadersState = PUTHEADERS_DONE;
825     SMTPState++;
826     }
827     break;
828    
829     case PUTHEADERS_OTHER:
830     if(SMTPClient.ROMPointers.OtherHeaders)
831     {
832     SMTPClient.OtherHeaders.szROM = TCPPutROMString(MySocket, SMTPClient.OtherHeaders.szROM);
833     if(*SMTPClient.OtherHeaders.szROM == 0)
834     {
835     TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
836     PutHeadersState = PUTHEADERS_DONE;
837     SMTPState++;
838     }
839     }
840     else
841     {
842     SMTPClient.OtherHeaders.szRAM = TCPPutString(MySocket, SMTPClient.OtherHeaders.szRAM);
843     if(*SMTPClient.OtherHeaders.szRAM == 0)
844     {
845     TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
846     PutHeadersState = PUTHEADERS_DONE;
847     SMTPState++;
848     }
849     }
850     break;
851     }
852     }
853     TCPFlush(MySocket);
854     break;
855    
856     case SMTP_DATA_BODY_INIT:
857     SMTPState++;
858     RAMStrPtr = SMTPClient.Body.szRAM;
859     ROMStrPtr2 = (ROM BYTE*)"\r\n.\r\n";
860     CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n.");
861     // No break here
862    
863     case SMTP_DATA_BODY:
864     if(SMTPClient.Body.szRAM || SMTPClient.Body.szROM)
865     {
866     if(*ROMStrPtr2)
867     {
868     // Put the application data, doing the transparancy replacement of "\r\n." with "\r\n.."
869     while(CRPeriod.Pos)
870     {
871     CRPeriod.Pos += 3;
872     RAMStrPtr += TCPPutArray(MySocket, RAMStrPtr, CRPeriod.Pos-RAMStrPtr);
873     if(RAMStrPtr == CRPeriod.Pos)
874     {
875     if(!TCPPut(MySocket, '.'))
876     {
877     CRPeriod.Pos -= 3;
878     break;
879     }
880     }
881     else
882     {
883     CRPeriod.Pos -= 3;
884     break;
885     }
886     CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n.");
887     }
888    
889     // If we get down here, either all replacements have been made or there is no remaining space in the TCP output buffer
890     RAMStrPtr = TCPPutString(MySocket, RAMStrPtr);
891     ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2);
892     TCPFlush(MySocket);
893     }
894     }
895     else
896     {
897     if(SMTPFlags.bits.ReadyToFinish)
898     {
899     if(*ROMStrPtr2)
900     {
901     ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2);
902     TCPFlush(MySocket);
903     }
904    
905     }
906     }
907    
908     if(*ROMStrPtr2 == 0u)
909     {
910     SMTPState++;
911     }
912     break;
913    
914     case SMTP_QUIT_INIT:
915     SMTPState++;
916     ROMStrPtr = (ROM BYTE*)"QUIT\r\n";
917     // No break here
918    
919     case SMTP_QUIT:
920     if(*ROMStrPtr)
921     {
922     ROMStrPtr = TCPPutROMString(MySocket, ROMStrPtr);
923     TCPFlush(MySocket);
924     }
925    
926     if(*ROMStrPtr == 0u)
927     {
928     TransportState = TRANSPORT_CLOSE;
929     }
930     break;
931     }
932     break;
933    
934     case TRANSPORT_CLOSE:
935     // Close the socket so it can be used by other modules
936     TCPDisconnect(MySocket);
937     MySocket = INVALID_SOCKET;
938    
939     // Go back to doing nothing
940     TransportState = TRANSPORT_HOME;
941     break;
942     }
943     }
944    
945     void SMTPSendMail(void)
946     {
947     SMTPFlags.bits.ReadyToStart = TRUE;
948     }
949    
950     BOOL SMTPIsBusy(void)
951     {
952     return TransportState != TRANSPORT_HOME;
953     }
954    
955     WORD SMTPIsPutReady(void)
956     {
957     if(SMTPState != SMTP_DATA_BODY)
958     return 0;
959    
960     return TCPIsPutReady(MySocket);
961     }
962    
963     BOOL SMTPPut(BYTE c)
964     {
965     if(CRPeriod.State == CR_PERIOD_NEED_INSERTION)
966     {
967     if(TCPPut(MySocket, '.'))
968     CRPeriod.State = CR_PERIOD_SEEK_CR;
969     else
970     return FALSE;
971     }
972    
973     switch(CRPeriod.State)
974     {
975     case CR_PERIOD_SEEK_CR:
976     if(c == '\r')
977     CRPeriod.State++;
978     break;
979    
980     case CR_PERIOD_SEEK_LF:
981     if(c == '\n')
982     CRPeriod.State++;
983     else if(c != '\r')
984     CRPeriod.State--;
985     break;
986    
987     case CR_PERIOD_SEEK_PERIOD:
988     if(c == '.')
989     CRPeriod.State++; // CR_PERIOD_NEED_INSERTION
990     else if(c == '\r')
991     CRPeriod.State--;
992     else
993     CRPeriod.State = CR_PERIOD_SEEK_CR;
994     break;
995     }
996    
997     if(!TCPPut(MySocket, c))
998     return FALSE;
999    
1000     return TRUE;
1001     }
1002    
1003     WORD SMTPPutArray(BYTE* Data, WORD Len)
1004     {
1005     WORD result = 0;
1006    
1007     // Must use SMTPPut() instead of TCPPutArray because of transparancy replacements of "\r\n." with "\r\n.."
1008     while(Len--)
1009     {
1010     if(SMTPPut(*Data++))
1011     {
1012     result++;
1013     }
1014     else
1015     {
1016     Data--;
1017     break;
1018     }
1019     }
1020    
1021     return result;
1022     }
1023     WORD SMTPPutROMArray(ROM BYTE* Data, WORD Len)
1024     {
1025     WORD result = 0;
1026    
1027     // Must use SMTPPut() instead of TCPPutArray because of transparancy replacements of "\r\n." with "\r\n.."
1028     while(Len--)
1029     {
1030     if(SMTPPut(*Data++))
1031     {
1032     result++;
1033     }
1034     else
1035     {
1036     Data--;
1037     break;
1038     }
1039     }
1040    
1041     return result;
1042     }
1043    
1044     WORD SMTPPutString(BYTE* Data)
1045     {
1046     WORD result = 0;
1047    
1048     // Must use SMTPPut() instead of TCPPutArray because of transparancy replacements of "\r\n." with "\r\n.."
1049     while(*Data)
1050     {
1051     if(SMTPPut(*Data++))
1052     {
1053     result++;
1054     }
1055     else
1056     {
1057     Data--;
1058     break;
1059     }
1060     }
1061    
1062     return result;
1063     }
1064    
1065     WORD SMTPPutROMString(ROM BYTE* Data)
1066     {
1067     WORD result = 0;
1068    
1069     // Must use SMTPPut() instead of TCPPutArray because of transparancy replacements of "\r\n." with "\r\n.."
1070     while(*Data)
1071     {
1072     if(SMTPPut(*Data++))
1073     {
1074     result++;
1075     }
1076     else
1077     {
1078     Data--;
1079     break;
1080     }
1081     }
1082    
1083     return result;
1084     }
1085    
1086     void SMTPFlush(void)
1087     {
1088     TCPFlush(MySocket);
1089     }
1090    
1091     void SMTPPutDone(void)
1092     {
1093     SMTPFlags.bits.ReadyToFinish = TRUE;
1094     }
1095    
1096    
1097     static BYTE *FindEmailAddress(BYTE *str, WORD *wLen)
1098     {
1099     BYTE *lpStart;
1100     BYTE c;
1101     union
1102     {
1103     BYTE Val;
1104     struct
1105     {
1106     BYTE FoundOpenBracket : 1;
1107     BYTE FoundAt : 1;
1108     } bits;
1109     } ParseStates;
1110    
1111     lpStart = str;
1112     *wLen = 0x0000;
1113     ParseStates.Val = 0x00;
1114    
1115     while(c = *str++)
1116     {
1117     if(c == '<')
1118     {
1119     ParseStates.bits.FoundOpenBracket = 1;
1120     lpStart = str;
1121     *wLen = -1;
1122     }
1123     else if(c == '@')
1124     ParseStates.bits.FoundAt = 1;
1125    
1126    
1127     if( !ParseStates.bits.FoundOpenBracket &&
1128     !ParseStates.bits.FoundAt &&
1129     (c == ' ' || c == ','))
1130     {
1131     lpStart = str;
1132     continue;
1133     }
1134     else if(c == ',')
1135     break;
1136    
1137     if(ParseStates.bits.FoundOpenBracket && ParseStates.bits.FoundAt)
1138     {
1139     if(c == '>')
1140     break;
1141     }
1142    
1143     // Advance to next character
1144     *wLen += 1;
1145     }
1146    
1147     if(!ParseStates.bits.FoundAt)
1148     *wLen = 0;
1149    
1150     return lpStart;
1151     }
1152    
1153     static ROM BYTE *FindROMEmailAddress(ROM BYTE *str, WORD *wLen)
1154     {
1155     ROM BYTE *lpStart;
1156     BYTE c;
1157     union
1158     {
1159     BYTE Val;
1160     struct
1161     {
1162     BYTE FoundOpenBracket : 1;
1163     BYTE FoundAt : 1;
1164     } bits;
1165     } ParseStates;
1166    
1167     lpStart = str;
1168     *wLen = 0x0000;
1169     ParseStates.Val = 0x00;
1170    
1171     while(c = *str++)
1172     {
1173     if(c == '<')
1174     {
1175     ParseStates.bits.FoundOpenBracket = 1;
1176     lpStart = str;
1177     *wLen = -1;
1178     }
1179     else if(c == '@')
1180     ParseStates.bits.FoundAt = 1;
1181    
1182    
1183     if( !ParseStates.bits.FoundOpenBracket &&
1184     !ParseStates.bits.FoundAt &&
1185     (c == ' ' || c == ','))
1186     {
1187     lpStart = str;
1188     continue;
1189     }
1190     else if(c == ',')
1191     break;
1192    
1193     if(ParseStates.bits.FoundOpenBracket && ParseStates.bits.FoundAt)
1194     {
1195     if(c == '>')
1196     break;
1197     }
1198    
1199     // Advance to next character
1200     *wLen += 1;
1201     }
1202    
1203     if(!ParseStates.bits.FoundAt)
1204     *wLen = 0;
1205    
1206     return lpStart;
1207     }
1208    
1209     #endif //#if defined(STACK_USE_SMTP_CLIENT)

  ViewVC Help
Powered by ViewVC 1.1.20