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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 31049 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
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