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.

316 lines
8.7 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: smtp.cxx
  7. //
  8. // Contents: Contains the command to send SMTP mail
  9. //
  10. // Stolen from KrisK's mail.exe tool.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "headers.hxx"
  14. #include <iostream.h>
  15. #include <winsock2.h>
  16. HRESULT
  17. CScriptHost::SendSMTPMail(BSTR bstrFrom,
  18. BSTR bstrTo,
  19. BSTR bstrCC,
  20. BSTR bstrSubject,
  21. BSTR bstrMessage,
  22. BSTR bstrSMTPHost,
  23. long *plError)
  24. {
  25. char achRecvBuf[2048];
  26. unsigned short port = 25;
  27. struct sockaddr_in Ser;
  28. struct hostent * hp;
  29. WSADATA wsaData;
  30. SOCKET conn_socket = INVALID_SOCKET;
  31. int iRet;
  32. int iLen;
  33. char achSendBuf[1024];
  34. char * pch;
  35. char * aszToList[30];
  36. int cToList = 0;
  37. char * aszCCList[30];
  38. int cCCList = 0;
  39. SYSTEMTIME stUT;
  40. int i;
  41. ANSIString szFrom(bstrFrom);
  42. ANSIString szTo(bstrTo);
  43. ANSIString szCC(bstrCC);
  44. ANSIString szSubject(bstrSubject);
  45. ANSIString szMessage(bstrMessage);
  46. ANSIString szSMTPHost(bstrSMTPHost);
  47. // ************** Parse the ToList into individual recipients
  48. pch = szTo;
  49. while (*pch && cToList < 30)
  50. {
  51. // Strip leading spaces from recipient name and terminate preceding
  52. // name string.
  53. if (isspace(*pch))
  54. {
  55. *pch=0;
  56. pch++;
  57. }
  58. // Add a name to the array and increment the number of recipients.
  59. else
  60. {
  61. aszToList[cToList++] = pch;
  62. // Move beginning of string to next name in ToList.
  63. do
  64. {
  65. pch++;
  66. } while (isgraph(*pch));
  67. }
  68. }
  69. // Parse the CCList into individual recipients
  70. pch = szCC;
  71. // Parse CCList into rgRecipDescStruct.
  72. while (*pch && cCCList < 30)
  73. {
  74. // Strip leading spaces from recipient name and terminate preceding
  75. // name string.
  76. if (isspace(*pch))
  77. {
  78. *pch=0;
  79. pch++;
  80. }
  81. // Add a name to the array and increment the number of recipients.
  82. else
  83. {
  84. aszCCList[cCCList++] = pch;
  85. // Move beginning of string to next name in CCList.
  86. do
  87. {
  88. pch++;
  89. } while (isgraph(*pch));
  90. }
  91. }
  92. // ************** Initialize Windows Sockets
  93. // BUGBUG -- Make error return code meaningful
  94. iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
  95. if (iRet != 0)
  96. {
  97. *plError = iRet;
  98. return S_OK;
  99. }
  100. hp = gethostbyname(szSMTPHost);
  101. if (hp == NULL)
  102. goto WSAError;
  103. memset(&Ser,0,sizeof(Ser));
  104. memcpy(&(Ser.sin_addr),hp->h_addr,hp->h_length);
  105. Ser.sin_family = hp->h_addrtype;
  106. Ser.sin_port = htons(port);
  107. // Open a socket
  108. conn_socket = socket(AF_INET, SOCK_STREAM, 0);
  109. if (conn_socket == INVALID_SOCKET)
  110. goto WSAError;
  111. // ************** Connect to the SMTP host
  112. iRet = connect(conn_socket, (struct sockaddr*)&Ser, sizeof(Ser));
  113. if (iRet == SOCKET_ERROR)
  114. goto WSAError;
  115. // Get the server's initial response
  116. iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
  117. if (iRet == SOCKET_ERROR)
  118. goto WSAError;
  119. // We expect code 220: "Service Ready"
  120. if (strncmp(achRecvBuf, "220", 3) != 0)
  121. goto ACKError;
  122. // ************** Send the mail command
  123. iLen = wsprintfA(achSendBuf, "MAIL FROM: <%s>\r\n", szFrom);
  124. iRet = send(conn_socket, achSendBuf, iLen, 0);
  125. if (iRet == SOCKET_ERROR)
  126. goto WSAError;
  127. iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
  128. if (iRet == SOCKET_ERROR)
  129. goto WSAError;
  130. // We expect code 250: "Requested mail action OK, completed"
  131. if (strncmp(achRecvBuf, "250", 3) != 0)
  132. goto ACKError;
  133. // ************** Send the recipient list (combination of TO and CC)
  134. for (i = 0; i < cToList; i++)
  135. {
  136. iLen = wsprintfA(achSendBuf, "RCPT TO: <%s>\r\n", aszToList[i]);
  137. iRet = send(conn_socket, achSendBuf, iLen, 0);
  138. if (iRet == SOCKET_ERROR)
  139. goto WSAError;
  140. iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
  141. if (iRet == SOCKET_ERROR)
  142. goto WSAError;
  143. // We expect code 250: "Requested mail action OK, completed"
  144. if (strncmp(achRecvBuf, "250", 3) != 0)
  145. goto ACKError;
  146. }
  147. for (i = 0; i < cCCList; i++)
  148. {
  149. iLen = wsprintfA(achSendBuf, "RCPT TO: <%s>\r\n", aszCCList[i]);
  150. iRet = send(conn_socket, achSendBuf, iLen, 0);
  151. if (iRet == SOCKET_ERROR)
  152. goto WSAError;
  153. iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
  154. if (iRet == SOCKET_ERROR)
  155. goto WSAError;
  156. // We expect code 250: "Requested mail action OK, completed"
  157. if (strncmp(achRecvBuf, "250", 3) != 0)
  158. goto ACKError;
  159. }
  160. // ************** Send the mail headers
  161. iLen = wsprintfA(achSendBuf, "DATA\r\n");
  162. iRet = send(conn_socket, achSendBuf, iLen, 0);
  163. if (iRet == SOCKET_ERROR)
  164. goto WSAError;
  165. iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
  166. if (iRet == SOCKET_ERROR)
  167. goto WSAError;
  168. // We expect code 354: "Start mail input; End with ."
  169. if (strncmp(achRecvBuf, "354", 3) != 0)
  170. goto ACKError;
  171. GetSystemTime(&stUT);
  172. GetDateFormatA(LOCALE_NEUTRAL,
  173. 0,
  174. &stUT,
  175. "dd MMM yy",
  176. achRecvBuf,
  177. sizeof(achRecvBuf));
  178. wsprintfA(achSendBuf,
  179. "Date: %s %02d:%02d UT\r\n",
  180. achRecvBuf,
  181. stUT.wHour,
  182. stUT.wMinute);
  183. iRet = send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
  184. if (iRet == SOCKET_ERROR)
  185. goto WSAError;
  186. wsprintfA(achSendBuf, "From: <%s>\r\n", szFrom);
  187. wsprintfA(&achSendBuf[strlen(achSendBuf)], "Subject: %s\r\n", szSubject);
  188. wsprintfA(&achSendBuf[strlen(achSendBuf)], "To: ");
  189. for (i = 0; i < cToList; i++)
  190. {
  191. wsprintfA(&achSendBuf[strlen(achSendBuf)],
  192. "<%s>%s",
  193. aszToList[i],
  194. (i == cToList-1) ? "\r\n" : ",\r\n ");
  195. }
  196. if (cCCList > 0)
  197. {
  198. wsprintfA(&achSendBuf[strlen(achSendBuf)], "cc: ", szFrom);
  199. for (i = 0; i < cCCList; i++)
  200. {
  201. wsprintfA(&achSendBuf[strlen(achSendBuf)],
  202. "<%s>%s",
  203. aszCCList[i],
  204. (i == cCCList-1) ? "\r\n" : ",\r\n ");
  205. }
  206. }
  207. wsprintfA(&achSendBuf[strlen(achSendBuf)], "Reply-To: <%s>\r\n\r\n", szFrom);
  208. /*
  209. BUGBUG -- Perhaps support HTML formatted mail in the future?
  210. if ( html )
  211. str += "MIME-Version: 1.0\r\nContent-Type: text/html;\r\n charset=\"iso-8859-1\"\r\nSUBJECT: "+ title + "\r\n\r\n"+ message +"\r\n.\r\n";
  212. */
  213. iRet = send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
  214. if (iRet == SOCKET_ERROR)
  215. goto WSAError;
  216. // ************** Send the message body
  217. iRet = send(conn_socket, szMessage, strlen(szMessage), 0);
  218. if (iRet == SOCKET_ERROR)
  219. goto WSAError;
  220. // ************** Close the connection
  221. strcpy(achSendBuf, "\r\n.\r\n");
  222. iRet = send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
  223. if (iRet == SOCKET_ERROR)
  224. goto WSAError;
  225. iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
  226. if (iRet == SOCKET_ERROR)
  227. goto WSAError;
  228. // We expect code 250: "Requested mail action OK, completed"
  229. if (strncmp(achRecvBuf, "250", 3) != 0)
  230. goto ACKError;
  231. strcpy(achSendBuf, "QUIT\r\n");
  232. send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
  233. Cleanup:
  234. if (conn_socket != INVALID_SOCKET)
  235. {
  236. closesocket(conn_socket);
  237. }
  238. WSACleanup();
  239. return S_OK;
  240. ACKError:
  241. // BUGBUG -- Preserve entire string that was returned
  242. achRecvBuf[3] = '\0';
  243. *plError = atoi(achRecvBuf);
  244. goto Cleanup;
  245. WSAError:
  246. *plError = WSAGetLastError();
  247. goto Cleanup;
  248. }