Leaked source code of windows server 2003
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.

268 lines
6.1 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, u_short 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. numRead = recv(sock, readBuffer, bufLen, 0);
  23. // recv can return SOCKET_ERROR which is -1, we don't want to underflow the buffer.
  24. if (numRead < 0)
  25. {
  26. numRead = 0;
  27. }
  28. //
  29. // NULL terminate read string
  30. //
  31. readBuffer[numRead] = 0;
  32. }
  33. //
  34. // Send a string specifying an SMTP command and read in response, returning
  35. // TRUE if it is the one expected.
  36. // Note the SMTP protocol is designed such that only the 1 character of the
  37. // response need be checked, but we check for the exact response (mostly cause
  38. // I just read that bit in the RFC)
  39. //
  40. BOOL SendAndExpect(SOCKET sock, char * sendBuffer, char * szExpect)
  41. {
  42. char readBuffer[READ_BUF_LEN];
  43. int len;
  44. int numSent;
  45. //
  46. // Send string to socket
  47. //
  48. numSent = send(sock, sendBuffer, lstrlenA(sendBuffer), 0);
  49. if (numSent == SOCKET_ERROR)
  50. {
  51. DBG_WARN("Error on send");
  52. return FALSE;
  53. }
  54. //
  55. // Now read in response
  56. //
  57. Read(sock, readBuffer, READ_BUF_LEN);
  58. DBG2("Sent: %s", sendBuffer);
  59. DBG2("Read: %s", readBuffer);
  60. //
  61. // Expect beginning of response to contain szExpect string
  62. //
  63. len = lstrlenA(szExpect);
  64. if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0,
  65. readBuffer, len, szExpect, len) == 2)
  66. {
  67. return TRUE;
  68. }
  69. else
  70. {
  71. return FALSE;
  72. }
  73. }
  74. #define SMTP_221 "221"
  75. #define SMTP_250 "250"
  76. #define SMTP_354 "354"
  77. #define SMTP_EOM "\r\n.\r\n"
  78. //
  79. // Carry out SMTP negotiation
  80. //
  81. BOOL SMTPSendEmail(SOCKET sock, char * szToAddress, char * szFromAddress, char *szMessage)
  82. {
  83. char sendBuffer[256];
  84. char readBuffer[READ_BUF_LEN];
  85. BOOL b = TRUE;
  86. int r, len;
  87. //
  88. // Read the opening response
  89. //
  90. Read(sock, readBuffer, sizeof(readBuffer));
  91. DBG(readBuffer);
  92. //
  93. // say Hello and specify my domain
  94. //
  95. b = SendAndExpect(sock, "HELO ActiveDesktop\r\n", SMTP_250);
  96. if (!b) goto done;
  97. //
  98. // First special sender in MAIL command
  99. //
  100. wnsprintfA(sendBuffer, ARRAYSIZE(sendBuffer), "MAIL FROM:<%s>\r\n",
  101. szFromAddress);
  102. b = SendAndExpect(sock, sendBuffer, SMTP_250);
  103. if (!b) goto done;
  104. //
  105. // Now specify recipient(s)
  106. //
  107. wnsprintfA(sendBuffer, ARRAYSIZE(sendBuffer), "RCPT TO:<%s>\r\n",
  108. szToAddress);
  109. b = SendAndExpect(sock, sendBuffer, SMTP_250);
  110. if (!b) goto done;
  111. //
  112. // Now send DATA command
  113. //
  114. b = SendAndExpect(sock, "DATA\r\n", SMTP_354);
  115. if (!b) goto done;
  116. //
  117. // Now send mail message
  118. //
  119. len = lstrlenA(szMessage);
  120. r = send(sock, szMessage, len, 0);
  121. ASSERT(r != SOCKET_ERROR);
  122. ASSERT(r == len);
  123. //
  124. // Specify end of message with single period.
  125. //
  126. b = SendAndExpect(sock, SMTP_EOM, SMTP_250);
  127. if (!b) goto done;
  128. //
  129. // Say goodbye
  130. //
  131. b = SendAndExpect(sock, "QUIT\r\n", SMTP_221);
  132. done:
  133. return b;
  134. }
  135. //
  136. // Main entry point -
  137. // start winsock dll,
  138. // connect to socket,
  139. // and negotiate transfer
  140. //
  141. SMTPSendMessage(char * szServer, char * szToAddress, char * szFromAddress, char * szMessage)
  142. {
  143. int err;
  144. SOCKET sock;
  145. BOOL b = FALSE;
  146. WSADATA wsaData;
  147. //
  148. // Init the winsock dll specifying which version we want.
  149. //
  150. err = WSAStartup((WORD)0x0101, &wsaData);
  151. if (err)
  152. {
  153. DBG_WARN("WinSock startup error");
  154. return FALSE;
  155. }
  156. DBG("WinSock successfully started");
  157. //
  158. // Actually form the socket connection to the host on port 25
  159. //
  160. sock = Connect(szServer, 25);
  161. if (sock != 0)
  162. {
  163. DBG("Connected");
  164. b = SMTPSendEmail(sock, szToAddress, szFromAddress, szMessage);
  165. }
  166. //
  167. // Done with winsock dll for now
  168. //
  169. WSACleanup();
  170. return b;
  171. }
  172. SOCKET
  173. Connect(char *host, u_short port)
  174. {
  175. struct sockaddr_in sockaddress;
  176. DWORD err;
  177. SOCKET sock, connectresult;
  178. //
  179. // Get the socket address
  180. //
  181. if(IS_DIGIT(*host))
  182. sockaddress.sin_addr.s_addr=inet_addr(host);
  183. else
  184. {
  185. struct hostent *hp;
  186. if((hp=gethostbyname(host))==NULL)
  187. {
  188. DBG_WARN2("Unknown host %s", host);
  189. return 0;
  190. }
  191. memcpy(&sockaddress.sin_addr, hp->h_addr, sizeof(sockaddress.sin_addr));
  192. }
  193. //
  194. // port address
  195. //
  196. sockaddress.sin_port=htons(port);
  197. sockaddress.sin_family=AF_INET;
  198. //
  199. // Create a stream style socket
  200. //
  201. if((sock=socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  202. DBG_WARN("socket error");
  203. DBG("Trying to connect");
  204. connectresult=connect(sock,(struct sockaddr *) &sockaddress, sizeof(sockaddress));
  205. if (connectresult == SOCKET_ERROR)
  206. {
  207. switch(err = WSAGetLastError())
  208. {
  209. case WSAECONNREFUSED:
  210. DBG_WARN("ERROR - CONNECTION REFUSED.");
  211. break;
  212. case WSAENETUNREACH:
  213. DBG_WARN("ERROR - THE NETWORK IS NOT REACHABLE FROM THIS HOST.");
  214. break;
  215. case WSAEINVAL:
  216. DBG_WARN("ERROR - The socket is not already bound to an address.");
  217. break;
  218. case WSAETIMEDOUT:
  219. DBG_WARN("ERROR - Connection timed out.");
  220. break;
  221. default:
  222. DBG_WARN2("Couldn't connect %d", err);
  223. break;
  224. }
  225. closesocket(sock);
  226. return 0;
  227. }
  228. return sock;
  229. }