embkernel
 All Classes Functions Variables Typedefs Groups Pages
NetClientSmtp.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "NetClientSmtp.hpp"
7 #include "NetClientDns.hpp"
8 #include <stdarg.h>
9 
10 const uint8_t NetClientSmtp::BASE64_INDEX_TABLE[] = {
11  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
12  'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
13  '8', '9', '+', '/' };
14 
15 bool NetClientSmtp::start(const char* server, bool authRequired, const char* user, const char* pass, const char* from, const char* to, const char* subject) {
16 
17  NetDefs::IP_ADDR serverAddr;
18 
19  if (!NetClientDns::resolve(server, &serverAddr)) {
20  return false;
21  }
22 
23  if (!mSocket.connect(serverAddr, 25)) {
24  return false;
25  }
26 
27  int replyCode = getReplyCode();
28  if (replyCode < 200 || replyCode >= 300) {
29  return false;
30  }
31 
32  mSocket.printf ("HELO %s\r\n", user);
33  replyCode = getReplyCode();
34  if (replyCode < 200 || replyCode >= 300) {
35  return false;
36  }
37 
38  if (authRequired) {
39  mSocket.printf ("AUTH LOGIN\r\n");
40  replyCode = getReplyCode();
41  if (replyCode < 300 || replyCode >= 400) {
42  return false;
43  }
44 
45  sendBase64(user);
46  mSocket.printf ("\r\n");
47  replyCode = getReplyCode();
48  if (replyCode < 300 || replyCode >= 400) {
49  return false;
50  }
51 
52  sendBase64(pass);
53  mSocket.printf ("\r\n");
54  replyCode = getReplyCode();
55  if (replyCode < 200 || replyCode >= 300) {
56  return false;
57  }
58  }
59 
60  mSocket.printf ("MAIL FROM:<%s>\r\n", from);
61  replyCode = getReplyCode();
62  if (replyCode < 200 || replyCode >= 300) {
63  return false;
64  }
65 
66  mSocket.printf ("RCPT TO:<%s>\r\n", to);
67  replyCode = getReplyCode();
68  if (replyCode < 200 || replyCode >= 300) {
69  return false;
70  }
71 
72  mSocket.printf ("DATA\r\n");
73  replyCode = getReplyCode();
74  if (replyCode < 300 || replyCode >= 400) {
75  return false;
76  }
77 
78  mSocket.printf ("from:<%s>\r\nsubject:%s\r\n\r\n", from, subject);
79 
80  return true;
81 }
82 
83 int NetClientSmtp::queueBody(const char* format, ...) {
84  va_list vaList;
85  int len;
86 
87  va_start(vaList, format);
88 
89  len = LibStringFormat::vprintf(mSocket,format, vaList);
90 
91  va_end(vaList);
92 
93  return len;
94 }
95 
96 bool NetClientSmtp::end() {
97  mSocket.printf("\r\n.\r\n");
98  mSocket.flush();
99  int replyCode = getReplyCode();
100  if (replyCode < 200 || replyCode >= 300) {
101  return false;
102  }
103  return true;
104 }
105 
106 void NetClientSmtp::closeConnection() {
107  mSocket.close();
108 }
109 
110 void NetClientSmtp::sendBase64(const char* string) {
111  int len = strlen(string);
112 
113  for (int i = 0; i < len;) {
114  int sentChars = 1;
115  uint32_t bitPattern = (uint32_t) string[i++] << 16;
116  if (i < len) {
117  bitPattern += (uint32_t) string[i++] << 8;
118  sentChars++;
119  }
120  if (i < len) {
121  bitPattern += (uint32_t) string[i++];
122  sentChars++;
123  }
124 
125  uint8_t encoded[4];
126 
127  encoded[0] = BASE64_INDEX_TABLE[(bitPattern >> 18) & 0x3F];
128  encoded[1] = BASE64_INDEX_TABLE[(bitPattern >> 12) & 0x3F];
129  encoded[2] = BASE64_INDEX_TABLE[(bitPattern >> 6) & 0x3F];
130  encoded[3] = BASE64_INDEX_TABLE[(bitPattern >> 0) & 0x3F];
131 
132  if (sentChars == 1) {
133  encoded[2] = '=';
134  encoded[3] = '=';
135  }
136  else if (sentChars == 2) {
137  encoded[3] = '=';
138  }
139 
140  mSocket.write(encoded, 4);
141  }
142 }
143 
144 int NetClientSmtp::getReplyCode() {
145  while (true) {
146 
147  uint8_t tmp[4];
148  if (mSocket.read(tmp, 4, Rtos::convertMsToTick(2000)) != 4) {
149  return -1;
150  }
151 
152  int replyCode = ((int) (tmp[0] - '0') * 100) + ((int) (tmp[1] - '0') * 10) + ((int) (tmp[2] - '0'));
153 
154  bool isLastLine = true;
155  if (tmp[3] == '-') {
156  isLastLine = false;
157  }
158 
159  while (true) { //Reach the end of the line
160  if (mSocket.read(tmp, 1, Rtos::convertMsToTick(2000)) != 1) {
161  return -1;
162  }
163  if (tmp[0] == '\n') {
164  if (isLastLine) {
165  return replyCode;
166  }
167  break;
168  }
169  }
170  }
171 }