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) { RakNet::Packet *packet; char query[1024]; TCPInterface tcpInterface; SystemAddress emailServer; if (tcpInterface.Start(0, 0)==false) return "Unknown error starting TCP"; emailServer=tcpInterface.Connect(hostAddress, hostPort,true); if (emailServer==UNASSIGNED_SYSTEM_ADDRESS) return "Failed to connect to host"; #if OPEN_SSL_CLIENT_SUPPORT==1 tcpInterface.StartSSLClient(emailServer); #endif RakNet::TimeMS timeoutTime = RakNet::GetTimeMS()+3000; packet=0; while (RakNet::GetTimeMS() < timeoutTime) { packet = tcpInterface.Receive(); if (packet) { if (doPrintf) RAKNET_DEBUG_PRINTF("%s", packet->data); break; } RakSleep(250); } if (packet==0) return "Timeout while waiting for initial data from server."; tcpInterface.Send("EHLO\r\n", 6, emailServer,false); const char *response; bool authenticate=false; #ifdef _MSC_VER #pragma warning(disable:4127) // conditional expression is constant #endif while (1) { response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0 && strcmp(response, "AUTHENTICATE")==0) { authenticate=true; break; } // Something other than continue? if (response!=0 && strcmp(response, "CONTINUE")!=0) return response; // Success? if (response==0) break; } if (authenticate) { sprintf(query, "EHLO %s\r\n", sender); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0) return response; if (password==0) return "Password needed"; char *outputData = RakNet::OP_NEW_ARRAY<char >((const int) (strlen(sender)+strlen(password)+2)*3, _FILE_AND_LINE_ ); RakNet::BitStream bs; char zero=0; bs.Write(&zero,1); bs.Write(sender,(const unsigned int)strlen(sender)); //bs.Write("*****@*****.**",(const unsigned int)strlen("*****@*****.**")); bs.Write(&zero,1); bs.Write(password,(const unsigned int)strlen(password)); bs.Write(&zero,1); //bs.Write("not.my.real.password",(const unsigned int)strlen("not.my.real.password")); Base64Encoding((const char*)bs.GetData(), bs.GetNumberOfBytesUsed(), outputData); sprintf(query, "AUTH PLAIN %s", outputData); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0) return response; } if (sender) sprintf(query, "MAIL From: <%s>\r\n", sender); else sprintf(query, "MAIL From: <>\r\n"); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0) return response; if (recipient) sprintf(query, "RCPT TO: <%s>\r\n", recipient); else sprintf(query, "RCPT TO: <>\r\n"); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0) return response; tcpInterface.Send("DATA\r\n", (unsigned int)strlen("DATA\r\n"), emailServer,false); // Wait for 354... response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0) return response; if (subject) { sprintf(query, "Subject: %s\r\n", subject); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); } if (senderName) { sprintf(query, "From: %s\r\n", senderName); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); } if (recipientName) { sprintf(query, "To: %s\r\n", recipientName); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); } const int boundarySize=60; char boundary[boundarySize+1]; int i,j; if (attachedFiles && attachedFiles->fileList.Size()) { rakNetRandom.SeedMT((unsigned int) RakNet::GetTimeMS()); // Random multipart message boundary for (i=0; i < boundarySize; i++) boundary[i]=Base64Map()[rakNetRandom.RandomMT()%64]; boundary[boundarySize]=0; } sprintf(query, "MIME-version: 1.0\r\n"); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); if (attachedFiles && attachedFiles->fileList.Size()) { sprintf(query, "Content-type: multipart/mixed; BOUNDARY=\"%s\"\r\n\r\n", boundary); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); sprintf(query, "This is a multi-part message in MIME format.\r\n\r\n--%s\r\n", boundary); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); } sprintf(query, "Content-Type: text/plain; charset=\"US-ASCII\"\r\n\r\n"); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); // Write the body of the email, doing some lame shitty shit where I have to make periods at the start of a newline have a second period. char *newBody; int bodyLength; bodyLength=(int)strlen(body); newBody = (char*) rakMalloc_Ex( bodyLength*3, _FILE_AND_LINE_ ); if (bodyLength>0) newBody[0]=body[0]; for (i=1, j=1; i < bodyLength; i++) { // Transform \n . \r \n into \n . . \r \n if (i < bodyLength-2 && body[i-1]=='\n' && body[i+0]=='.' && body[i+1]=='\r' && body[i+2]=='\n') { newBody[j++]='.'; newBody[j++]='.'; newBody[j++]='\r'; newBody[j++]='\n'; i+=2; } // Transform \n . . \r \n into \n . . . \r \n // Having to process .. is a bug in the mail server - the spec says ONLY \r\n.\r\n should be transformed else if (i <= bodyLength-3 && body[i-1]=='\n' && body[i+0]=='.' && body[i+1]=='.' && body[i+2]=='\r' && body[i+3]=='\n') { newBody[j++]='.'; newBody[j++]='.'; newBody[j++]='.'; newBody[j++]='\r'; newBody[j++]='\n'; i+=3; } // Transform \n . \n into \n . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does) else if (i < bodyLength-1 && body[i-1]=='\n' && body[i+0]=='.' && body[i+1]=='\n') { newBody[j++]='.'; newBody[j++]='.'; newBody[j++]='\r'; newBody[j++]='\n'; i+=1; } // Transform \n . . \n into \n . . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does) // In fact having to process .. is a bug too - because the spec says ONLY \r\n.\r\n should be transformed else if (i <= bodyLength-2 && body[i-1]=='\n' && body[i+0]=='.' && body[i+1]=='.' && body[i+2]=='\n') { newBody[j++]='.'; newBody[j++]='.'; newBody[j++]='.'; newBody[j++]='\r'; newBody[j++]='\n'; i+=2; } else newBody[j++]=body[i]; } newBody[j++]='\r'; newBody[j++]='\n'; tcpInterface.Send(newBody, j, emailServer,false); rakFree_Ex(newBody, _FILE_AND_LINE_ ); int outputOffset; // What a pain in the rear. I have to map the binary to printable characters using 6 bits per character. if (attachedFiles && attachedFiles->fileList.Size()) { for (i=0; i < (int) attachedFiles->fileList.Size(); i++) { // Write boundary sprintf(query, "\r\n--%s\r\n", boundary); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); 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()); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); newBody = (char*) rakMalloc_Ex( (size_t) (attachedFiles->fileList[i].dataLengthBytes*3)/2, _FILE_AND_LINE_ ); outputOffset=Base64Encoding(attachedFiles->fileList[i].data, (int) attachedFiles->fileList[i].dataLengthBytes, newBody); // Send the base64 mapped file. tcpInterface.Send(newBody, outputOffset, emailServer,false); rakFree_Ex(newBody, _FILE_AND_LINE_ ); } // Write last boundary sprintf(query, "\r\n--%s--\r\n", boundary); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); } sprintf(query, "\r\n.\r\n"); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); response=GetResponse(&tcpInterface, emailServer, doPrintf); if (response!=0) return response; tcpInterface.Send("QUIT\r\n", (unsigned int)strlen("QUIT\r\n"), emailServer,false); RakSleep(30); if (doPrintf) { packet = tcpInterface.Receive(); while (packet) { RAKNET_DEBUG_PRINTF("%s", packet->data); packet = tcpInterface.Receive(); } } tcpInterface.Stop(); return 0; // Success }
void main_RakNet(void) { const char *serverURL = "localhost"; //const char *serverURL = "lobby3.raknet.com"; //const unsigned int serverPort=80; //const unsigned int serverPort=8888; //const bool useSSL=true; const bool useSSL=false; //const unsigned int serverPort=443; const unsigned int serverPort=8080; json_t *jsonObject = json_object(); json_object_set(jsonObject, "__devId", json_string("defaultDevId1")); json_object_set(jsonObject, "__userId", json_string("defaultUserId1")); json_object_set(jsonObject, "__userPw", json_string("defaultPw")); json_object_set(jsonObject, "__appId", json_string("defaultAppId1")); json_object_set(jsonObject, "__customTableId", json_string("defaultCustomTableId")); json_object_set(jsonObject, "__timeToLiveSec", json_integer(0)); json_object_set(jsonObject, "__timeToIdleSec", json_integer(6000)); json_object_set(jsonObject, "__key", json_integer(0)); json_object_set(jsonObject, "__mergeMode", json_string("OVERWRITE_EXISTING")); //json_object_set(jsonObject, "__autoFields", json_string("svrTimestamp,svrIP,svrSerial,svrGeoIP")); json_object_set(jsonObject, "__fieldMetadata", json_string("sampleField1Key(_ownerRW,_putMin),sampleField2Key(_userRW,_putSum)")); json_object_set(jsonObject, "__protocol", json_integer(0)); json_object_set(jsonObject, "sampleField1Key", json_integer(1)); json_object_set(jsonObject, "sampleField2Key", json_integer(2)); // JSON_COMPACT is required or it won't match json-lib char *jsonStr = json_dumps(jsonObject, JSON_COMPACT | JSON_PRESERVE_ORDER); printf(jsonStr); // For testing, see http://hash.online-convert.com/sha1-generator const char *__sharedKey="defaultSharedKey"; unsigned char output[SHA1_LENGTH]; CSHA1::HMAC((unsigned char*) __sharedKey, strlen(__sharedKey), (unsigned char*) jsonStr, strlen(jsonStr), output); char outputBase64[SHA1_LENGTH*2+6]; int bytesWritten = Base64Encoding(output, sizeof(output), outputBase64); //outputBase64[bytesWritten]=0; json_object_set(jsonObject, "__hash", json_string(outputBase64)); jsonStr = json_dumps(jsonObject, JSON_COMPACT | JSON_PRESERVE_ORDER); // GAE SSL https://developers.google.com/appengine/docs/ssl char URI[128]; sprintf(URI, "%s/customTable/update", serverURL); TCPInterface *tcp = RakNet::OP_NEW<TCPInterface>(__FILE__,__LINE__); // Requires build with OPEN_SSL_CLIENT_SUPPORT tcp->Start(0, 64); tcp->Connect(serverURL, serverPort, true); RakString rspost = RakString::FormatForPOST( URI, RakString("text/plain; charset=UTF-8"), jsonStr ); RakSleep(100); SystemAddress serverAddr = tcp->HasCompletedConnectionAttempt(); RakAssert(serverAddr!=UNASSIGNED_SYSTEM_ADDRESS); if (useSSL) tcp->StartSSLClient(serverAddr); tcp->Send(rspost.C_String(), rspost.GetLength(), serverAddr, false); RakSleep(1000); Packet *p; while (1) { p = tcp->Receive(); if (p) { printf((const char*) p->data); break; } } }