00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_EmailSender==1
00003
00004
00005
00006
00007
00008
00009 #include "EmailSender.h"
00010 #include "TCPInterface.h"
00011 #include "GetTime.h"
00012 #include "Rand.h"
00013 #include "FileList.h"
00014 #include "BitStream.h"
00015 #include <stdio.h>
00016
00017 #if defined(_XBOX) || defined(X360)
00018
00019 #endif
00020
00021 #include "RakSleep.h"
00022
00023 static const char base64Map[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00024
00025 const char *EmailSender::Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password)
00026 {
00027 Packet *packet;
00028 char query[1024];
00029 TCPInterface tcpInterface;
00030 SystemAddress emailServer;
00031 if (tcpInterface.Start(0, 0)==false)
00032 return "Unknown error starting TCP";
00033 emailServer=tcpInterface.Connect(hostAddress, hostPort,true);
00034 if (emailServer==UNASSIGNED_SYSTEM_ADDRESS)
00035 return "Failed to connect to host";
00036 #ifdef OPEN_SSL_CLIENT_SUPPORT
00037 tcpInterface.StartSSLClient(emailServer);
00038 #endif
00039 RakNetTime timeoutTime = RakNet::GetTime()+3000;
00040 packet=0;
00041 while (RakNet::GetTime() < timeoutTime)
00042 {
00043 packet = tcpInterface.Receive();
00044 if (packet)
00045 {
00046 if (doPrintf)
00047 RAKNET_DEBUG_PRINTF("%s", packet->data);
00048 break;
00049 }
00050 RakSleep(250);
00051 }
00052
00053 if (packet==0)
00054 return "Timeout while waiting for initial data from server.";
00055
00056 tcpInterface.Send("EHLO\r\n", 6, emailServer,false);
00057 const char *response;
00058 bool authenticate=false;
00059 #ifdef _MSC_VER
00060 #pragma warning(disable:4127) // conditional expression is constant
00061 #endif
00062 while (1)
00063 {
00064 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00065
00066 if (response!=0 && strcmp(response, "AUTHENTICATE")==0)
00067 {
00068 authenticate=true;
00069 break;
00070 }
00071
00072
00073 if (response!=0 && strcmp(response, "CONTINUE")!=0)
00074 return response;
00075
00076
00077 if (response==0)
00078 break;
00079 }
00080
00081 if (authenticate)
00082 {
00083 sprintf(query, "EHLO %s\r\n", sender);
00084 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00085 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00086 if (response!=0)
00087 return response;
00088 if (password==0)
00089 return "Password needed";
00090 char *outputData = RakNet::OP_NEW_ARRAY<char >((const int) (strlen(sender)+strlen(password)+2)*3, __FILE__, __LINE__ );
00091 RakNet::BitStream bs;
00092 char zero=0;
00093 bs.Write(&zero,1);
00094 bs.Write(sender,(const unsigned int)strlen(sender));
00095
00096 bs.Write(&zero,1);
00097 bs.Write(password,(const unsigned int)strlen(password));
00098 bs.Write(&zero,1);
00099
00100 Base64Encoding((const char*)bs.GetData(), bs.GetNumberOfBytesUsed(), outputData, base64Map);
00101 sprintf(query, "AUTH PLAIN %s", outputData);
00102 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00103 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00104 if (response!=0)
00105 return response;
00106 }
00107
00108
00109 if (sender)
00110 sprintf(query, "MAIL From: <%s>\r\n", sender);
00111 else
00112 sprintf(query, "MAIL From: <>\r\n");
00113 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00114 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00115 if (response!=0)
00116 return response;
00117
00118 if (recipient)
00119 sprintf(query, "RCPT TO: <%s>\r\n", recipient);
00120 else
00121 sprintf(query, "RCPT TO: <>\r\n");
00122 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00123 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00124 if (response!=0)
00125 return response;
00126
00127 tcpInterface.Send("DATA\r\n", (unsigned int)strlen("DATA\r\n"), emailServer,false);
00128
00129
00130
00131 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00132 if (response!=0)
00133 return response;
00134
00135 if (subject)
00136 {
00137 sprintf(query, "Subject: %s\r\n", subject);
00138 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00139 }
00140 if (senderName)
00141 {
00142 sprintf(query, "From: %s\r\n", senderName);
00143 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00144 }
00145 if (recipientName)
00146 {
00147 sprintf(query, "To: %s\r\n", recipientName);
00148 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00149 }
00150
00151 const int boundarySize=60;
00152 char boundary[boundarySize+1];
00153 int i,j;
00154 if (attachedFiles && attachedFiles->fileList.Size())
00155 {
00156 seedMT((unsigned int) RakNet::GetTime());
00157
00158 for (i=0; i < boundarySize; i++)
00159 boundary[i]=base64Map[randomMT()%64];
00160 boundary[boundarySize]=0;
00161 }
00162
00163 sprintf(query, "MIME-version: 1.0\r\n");
00164 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00165
00166 if (attachedFiles && attachedFiles->fileList.Size())
00167 {
00168 sprintf(query, "Content-type: multipart/mixed; BOUNDARY=\"%s\"\r\n\r\n", boundary);
00169 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00170
00171 sprintf(query, "This is a multi-part message in MIME format.\r\n\r\n--%s\r\n", boundary);
00172 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00173 }
00174
00175 sprintf(query, "Content-Type: text/plain; charset=\"US-ASCII\"\r\n\r\n");
00176 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00177
00178
00179 char *newBody;
00180 int bodyLength;
00181 bodyLength=(int)strlen(body);
00182 newBody = (char*) rakMalloc_Ex( bodyLength*3, __FILE__, __LINE__ );
00183 if (bodyLength>0)
00184 newBody[0]=body[0];
00185 for (i=1, j=1; i < bodyLength; i++)
00186 {
00187
00188 if (i < bodyLength-2 &&
00189 body[i-1]=='\n' &&
00190 body[i+0]=='.' &&
00191 body[i+1]=='\r' &&
00192 body[i+2]=='\n')
00193 {
00194 newBody[j++]='.';
00195 newBody[j++]='.';
00196 newBody[j++]='\r';
00197 newBody[j++]='\n';
00198 i+=2;
00199 }
00200
00201
00202 else if (i <= bodyLength-3 &&
00203 body[i-1]=='\n' &&
00204 body[i+0]=='.' &&
00205 body[i+1]=='.' &&
00206 body[i+2]=='\r' &&
00207 body[i+3]=='\n')
00208 {
00209 newBody[j++]='.';
00210 newBody[j++]='.';
00211 newBody[j++]='.';
00212 newBody[j++]='\r';
00213 newBody[j++]='\n';
00214 i+=3;
00215 }
00216
00217 else if (i < bodyLength-1 &&
00218 body[i-1]=='\n' &&
00219 body[i+0]=='.' &&
00220 body[i+1]=='\n')
00221 {
00222 newBody[j++]='.';
00223 newBody[j++]='.';
00224 newBody[j++]='\r';
00225 newBody[j++]='\n';
00226 i+=1;
00227 }
00228
00229
00230 else if (i <= bodyLength-2 &&
00231 body[i-1]=='\n' &&
00232 body[i+0]=='.' &&
00233 body[i+1]=='.' &&
00234 body[i+2]=='\n')
00235 {
00236 newBody[j++]='.';
00237 newBody[j++]='.';
00238 newBody[j++]='.';
00239 newBody[j++]='\r';
00240 newBody[j++]='\n';
00241 i+=2;
00242 }
00243 else
00244 newBody[j++]=body[i];
00245 }
00246
00247 newBody[j++]='\r';
00248 newBody[j++]='\n';
00249 tcpInterface.Send(newBody, j, emailServer,false);
00250
00251 rakFree_Ex(newBody, __FILE__, __LINE__ );
00252 int outputOffset;
00253
00254
00255 if (attachedFiles && attachedFiles->fileList.Size())
00256 {
00257 for (i=0; i < (int) attachedFiles->fileList.Size(); i++)
00258 {
00259
00260 sprintf(query, "\r\n--%s\r\n", boundary);
00261 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00262
00263 sprintf(query, "Content-Type: APPLICATION/Octet-Stream; SizeOnDisk=%i; name=\"%s\"\r\nContent-Transfer-Encoding: BASE64\r\nContent-Description: %s\r\n\r\n", attachedFiles->fileList[i].dataLengthBytes, attachedFiles->fileList[i].filename.C_String(), attachedFiles->fileList[i].filename.C_String());
00264 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00265
00266 newBody = (char*) rakMalloc_Ex( (size_t) (attachedFiles->fileList[i].dataLengthBytes*3)/2, __FILE__, __LINE__ );
00267
00268 outputOffset=Base64Encoding(attachedFiles->fileList[i].data, (int) attachedFiles->fileList[i].dataLengthBytes, newBody, base64Map);
00269
00270
00271 tcpInterface.Send(newBody, outputOffset, emailServer,false);
00272 rakFree_Ex(newBody, __FILE__, __LINE__ );
00273
00274 }
00275
00276
00277 sprintf(query, "\r\n--%s--\r\n", boundary);
00278 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00279 }
00280
00281
00282 sprintf(query, "\r\n.\r\n");
00283 tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
00284 response=GetResponse(&tcpInterface, emailServer, doPrintf);
00285 if (response!=0)
00286 return response;
00287
00288 tcpInterface.Send("QUIT\r\n", (unsigned int)strlen("QUIT\r\n"), emailServer,false);
00289
00290 RakSleep(30);
00291 if (doPrintf)
00292 {
00293 packet = tcpInterface.Receive();
00294 while (packet)
00295 {
00296 RAKNET_DEBUG_PRINTF("%s", packet->data);
00297 packet = tcpInterface.Receive();
00298 }
00299 }
00300 tcpInterface.Stop();
00301 return 0;
00302 }
00303
00304 const char *EmailSender::GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf)
00305 {
00306 Packet *packet;
00307 RakNetTime timeout;
00308 timeout=RakNet::GetTime()+5000;
00309 #ifdef _MSC_VER
00310 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
00311 #endif
00312 while (1)
00313 {
00314 if (tcpInterface->HasLostConnection()==emailServer)
00315 return "Connection to server lost.";
00316 packet = tcpInterface->Receive();
00317 if (packet)
00318 {
00319 if (doPrintf)
00320 {
00321 RAKNET_DEBUG_PRINTF("%s", packet->data);
00322 }
00323 #if defined(OPEN_SSL_CLIENT_SUPPORT)
00324 if (strstr((const char*)packet->data, "220"))
00325 {
00326 tcpInterface->StartSSLClient(packet->systemAddress);
00327 return "AUTHENTICATE";
00328 }
00329
00330
00331
00332
00333
00334 #endif
00335 if (strstr((const char*)packet->data, "235"))
00336 return 0;
00337 if (strstr((const char*)packet->data, "354"))
00338 return 0;
00339 #if defined(OPEN_SSL_CLIENT_SUPPORT)
00340 if (strstr((const char*)packet->data, "250-STARTTLS"))
00341 {
00342 tcpInterface->Send("STARTTLS\r\n", (unsigned int) strlen("STARTTLS\r\n"), packet->systemAddress, false);
00343 return "CONTINUE";
00344 }
00345 #endif
00346 if (strstr((const char*)packet->data, "250"))
00347 return 0;
00348 if (strstr((const char*)packet->data, "550"))
00349 return "Failed on error code 550";
00350 if (strstr((const char*)packet->data, "553"))
00351 return "Failed on error code 553";
00352 }
00353 if (RakNet::GetTime() > timeout)
00354 return "Timed out";
00355 RakSleep(100);
00356 }
00357 }
00358
00359 int EmailSender::Base64Encoding(const char *inputData, int dataLength, char *outputData, const char *base64Map)
00360 {
00361 int outputOffset, charCount;
00362 int write3Count;
00363 outputOffset=0;
00364 charCount=0;
00365 int j;
00366
00367 write3Count=dataLength/3;
00368 for (j=0; j < write3Count; j++)
00369 {
00370
00371 outputData[outputOffset++]=base64Map[inputData[j*3+0] >> 2];
00372 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00373
00374
00375 outputData[outputOffset++]=base64Map[((inputData[j*3+0] << 4) | (inputData[j*3+1] >> 4)) & 63];
00376 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00377
00378
00379 outputData[outputOffset++]=base64Map[((inputData[j*3+1] << 2) | (inputData[j*3+2] >> 6)) & 63];
00380 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00381
00382
00383 outputData[outputOffset++]=base64Map[inputData[j*3+2] & 63];
00384 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00385 }
00386
00387 if (dataLength % 3==1)
00388 {
00389
00390 outputData[outputOffset++]=base64Map[inputData[j*3+0] >> 2];
00391 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00392
00393
00394 outputData[outputOffset++]=base64Map[((inputData[j*3+0] << 4) | (inputData[j*3+1] >> 4)) & 63];
00395 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00396
00397
00398 outputData[outputOffset++]='=';
00399 outputData[outputOffset++]='=';
00400 }
00401 else if (dataLength % 3==2)
00402 {
00403
00404
00405
00406 outputData[outputOffset++]=base64Map[inputData[j*3+0] >> 2];
00407 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00408
00409
00410 outputData[outputOffset++]=base64Map[((inputData[j*3+0] << 4) | (inputData[j*3+1] >> 4)) & 63];
00411 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00412
00413
00414 outputData[outputOffset++]=base64Map[(inputData[j*3+1] << 2) & 63];
00415 if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
00416
00417
00418 outputData[outputOffset++]='=';
00419
00420 }
00421
00422
00423 outputData[outputOffset++]='\r';
00424 outputData[outputOffset++]='\n';
00425 outputData[outputOffset]=0;
00426
00427 return outputOffset;
00428 }
00429
00430 #endif // _RAKNET_SUPPORT_*