Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
6.7 KiB

  1. //
  2. // SMTP - Simple Mail Transfer Protocol Code
  3. //
  4. // Implements sends mail using SMTP RFC 821.
  5. // Julian Jiggins, 12 January 1997
  6. //
  7. #include "private.h"
  8. #include <winsock.h>
  9. #define TF_THISMODULE TF_MAILAGENT
  10. #define IS_DIGIT(ch) InRange(ch, TEXT('0'), TEXT('9'))
  11. //
  12. // Function prototypes for this module
  13. //
  14. SOCKET Connect(char *host, char *port);
  15. #define READ_BUF_LEN 512
  16. //
  17. // Read all you can from a socket
  18. //
  19. void Read(SOCKET sock, char * readBuffer, int bufLen)
  20. {
  21. int numRead;
  22. int totalRead = 0;
  23. do
  24. {
  25. numRead = recv(sock, readBuffer+totalRead, bufLen, 0);
  26. totalRead += numRead;
  27. }
  28. while (0);
  29. // while (numRead > 0);
  30. //
  31. // NULL terminate read string
  32. //
  33. readBuffer[totalRead] = 0;
  34. }
  35. //
  36. // Send a string specifying an SMTP command and read in response, returning
  37. // TRUE if it is the one expected.
  38. // Note the SMTP protocol is designed such that only the 1 character of the
  39. // response need be checked, but we check for the exact response (mostly cause
  40. // I just read that bit in the RFC)
  41. //
  42. BOOL SendAndExpect(SOCKET sock, char * sendBuffer, char * szExpect)
  43. {
  44. char readBuffer[READ_BUF_LEN];
  45. int len;
  46. int numSent;
  47. //
  48. // Send string to socket
  49. //
  50. numSent = send(sock, sendBuffer, lstrlenA(sendBuffer), 0);
  51. if (numSent == SOCKET_ERROR)
  52. {
  53. DBG_WARN("Error on send");
  54. return FALSE;
  55. }
  56. //
  57. // Now read in response
  58. //
  59. Read(sock, readBuffer, READ_BUF_LEN);
  60. DBG2("Sent: %s", sendBuffer);
  61. DBG2("Read: %s", readBuffer);
  62. //
  63. // Expect beginning of response to contain szExpect string
  64. //
  65. len = lstrlenA(szExpect);
  66. if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0,
  67. readBuffer, len, szExpect, len) == 2)
  68. {
  69. return TRUE;
  70. }
  71. else
  72. {
  73. return FALSE;
  74. }
  75. }
  76. #define SMTP_221 "221"
  77. #define SMTP_250 "250"
  78. #define SMTP_354 "354"
  79. #define SMTP_EOM "\r\n.\r\n"
  80. //
  81. // Carry out SMTP negotiation
  82. //
  83. BOOL SMTPSendEmail(SOCKET sock, char * szToAddress, char * szFromAddress, char *szMessage)
  84. {
  85. char sendBuffer[256];
  86. char readBuffer[READ_BUF_LEN];
  87. BOOL b = TRUE;
  88. int r, len;
  89. //
  90. // Read the opening response
  91. //
  92. Read(sock, readBuffer, sizeof(readBuffer));
  93. DBG(readBuffer);
  94. //
  95. // say Hello and specify my domain
  96. //
  97. b = SendAndExpect(sock, "HELO ActiveDesktop\r\n", SMTP_250);
  98. if (!b) goto done;
  99. //
  100. // First special sender in MAIL command
  101. //
  102. wnsprintfA(sendBuffer, ARRAYSIZE(sendBuffer), "MAIL FROM:<%s>\r\n",
  103. szFromAddress);
  104. b = SendAndExpect(sock, sendBuffer, SMTP_250);
  105. if (!b) goto done;
  106. //
  107. // Now specify recipient(s)
  108. //
  109. wnsprintfA(sendBuffer, ARRAYSIZE(sendBuffer), "RCPT TO:<%s>\r\n",
  110. szToAddress);
  111. b = SendAndExpect(sock, sendBuffer, SMTP_250);
  112. if (!b) goto done;
  113. //
  114. // Now send DATA command
  115. //
  116. b = SendAndExpect(sock, "DATA\r\n", SMTP_354);
  117. if (!b) goto done;
  118. //
  119. // Now send mail message
  120. //
  121. len = lstrlenA(szMessage);
  122. r = send(sock, szMessage, len, 0);
  123. ASSERT(r != SOCKET_ERROR);
  124. ASSERT(r == len);
  125. //
  126. // Specify end of message with single period.
  127. //
  128. b = SendAndExpect(sock, SMTP_EOM, SMTP_250);
  129. if (!b) goto done;
  130. //
  131. // Say goodbye
  132. //
  133. b = SendAndExpect(sock, "QUIT\r\n", SMTP_221);
  134. done:
  135. return b;
  136. }
  137. //
  138. // Main entry point -
  139. // start winsock dll,
  140. // connect to socket,
  141. // and negotiate transfer
  142. //
  143. SMTPSendMessage(char * szServer, char * szToAddress, char * szFromAddress, char * szMessage)
  144. {
  145. int err;
  146. SOCKET sock;
  147. BOOL b = FALSE;
  148. WSADATA wsaData;
  149. //
  150. // Init the winsock dll specifying which version we want.
  151. //
  152. err = WSAStartup((WORD)0x0101, &wsaData);
  153. if (err)
  154. {
  155. DBG_WARN("WinSock startup error");
  156. return FALSE;
  157. }
  158. DBG("WinSock successfully started");
  159. //
  160. // Actually form the socket connection to the host on port 25
  161. //
  162. sock = Connect(szServer, "25");
  163. if (sock != 0)
  164. {
  165. DBG("Connected");
  166. b = SMTPSendEmail(sock, szToAddress, szFromAddress, szMessage);
  167. }
  168. //
  169. // Done with winsock dll for now
  170. //
  171. WSACleanup();
  172. return b;
  173. }
  174. #ifdef TEST
  175. int
  176. main(int argc, char * argv[])
  177. {
  178. char szMessage[1024];
  179. BOOL b;
  180. //
  181. // Build message
  182. //
  183. lstrcpy(szMessage, "Subject: Subscription Updated: CNN Interactive\r\n");
  184. lstrcat(szMessage, "Your subscription to CNN Interactive Subscription has been updated\r\n\r\n");
  185. lstrcat(szMessage, "To view the subscription offline, just click here: ");
  186. lstrcat(szMessage, "http://www.cnn.com\r\n");
  187. lstrcat(szMessage, "\r\nThis message was sent by the IE4.0 Information Delivery Agent\r\n");
  188. lstrcat(szMessage, "\r\n\r\n\r\nDoes this look okay guys? Julian.");
  189. b = SMTPSendMessage("saranac", "[email protected]", szMessage);
  190. if (b)
  191. DBG("Sent mail successfully");
  192. else
  193. DBG("Couldn't send email");
  194. return 0;
  195. }
  196. #endif
  197. SOCKET
  198. Connect(char *host, char *port)
  199. {
  200. struct sockaddr_in sockaddress;
  201. DWORD err;
  202. SOCKET sock, connectresult;
  203. //
  204. // Get the socket address
  205. //
  206. if(IS_DIGIT(*host))
  207. sockaddress.sin_addr.s_addr=inet_addr(host);
  208. else
  209. {
  210. struct hostent *hp;
  211. if((hp=gethostbyname(host))==NULL)
  212. {
  213. DBG_WARN2("Unknown host %s", host);
  214. return 0;
  215. }
  216. memcpy(&sockaddress.sin_addr, hp->h_addr, sizeof(sockaddress.sin_addr));
  217. }
  218. //
  219. // Get the port address
  220. //
  221. if(IS_DIGIT(*port))
  222. sockaddress.sin_port=htons((USHORT)StrToIntA(port));
  223. else
  224. {
  225. DBG_WARN("The port should be a number");
  226. return 0;
  227. }
  228. sockaddress.sin_family=AF_INET;
  229. //
  230. // Create a stream style socket
  231. //
  232. if((sock=socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  233. DBG_WARN("socket error");
  234. DBG("Trying to connect");
  235. connectresult=connect(sock,(struct sockaddr *) &sockaddress, sizeof(sockaddress));
  236. if (connectresult == SOCKET_ERROR)
  237. {
  238. switch(err = WSAGetLastError())
  239. {
  240. case WSAECONNREFUSED:
  241. DBG_WARN("ERROR - CONNECTION REFUSED.");
  242. break;
  243. case WSAENETUNREACH:
  244. DBG_WARN("ERROR - THE NETWORK IS NOT REACHABLE FROM THIS HOST.");
  245. break;
  246. case WSAEINVAL:
  247. DBG_WARN("ERROR - The socket is not already bound to an address.");
  248. break;
  249. case WSAETIMEDOUT:
  250. DBG_WARN("ERROR - Connection timed out.");
  251. break;
  252. default:
  253. DBG_WARN2("Couldn't connect %d", err);
  254. break;
  255. }
  256. closesocket(sock);
  257. return 0;
  258. }
  259. return sock;
  260. }