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)
|