Click here to Skip to main content
15,891,184 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I'm successfully able to send email using libcurl from visual c++ (in debug mode), but when I use release mode I'm getting following error:
> MAIL FROM:<xxxx@gmail.com> SIZE=22322250707370015
< 555 5.5.2 Syntax error. vx10sm168176313pac.17 - gsmtp


My code is :
C++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <string>
#include <cassert>
#include <limits>
#include <stdexcept>
#include <ctime>

#define _WINSOCKAPI_
#include <windows.h>

#define FROM    "<xxxx@gmail.com>"
#define TO      "<xxxx@gmail.com>"
#define FILENAME "edgE0DF.tmp"

static const int CHARS= 200;			//Sending 54 chararcters at a time with \r , \n and \0 it becomes 57 
static const int ADD_SIZE= 7;			// ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
static const int SEND_BUF_SIZE= 54;
static char (*fileBuf)[CHARS] = NULL;

struct fileBuf_upload_status 
{
  int lines_read;
};

static const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const char reverse_table[128] = {
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
   52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
   64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
   64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64
};

std::string base64_encode(const ::std::string &bindata)
{
   using ::std::string;
   using ::std::numeric_limits;

   //if (bindata.size() > (numeric_limits<string::size_type>::max() / 4u) * 3u) {
   //   throw ::std::length_error("Converting too large a string to base64.");
   //}

   const ::std::size_t binlen = bindata.size();
   // Use = signs so the end is properly padded.
   string retval((((binlen + 2) / 3) * 4), '=');
   ::std::size_t outpos = 0;
   int bits_collected = 0;
   unsigned int accumulator = 0;
   const string::const_iterator binend = bindata.end();

   for (string::const_iterator i = bindata.begin(); i != binend; ++i) {
      accumulator = (accumulator << 8) | (*i & 0xffu);
      bits_collected += 8;
      while (bits_collected >= 6) {
         bits_collected -= 6;
         retval[outpos++] = b64_table[(accumulator >> bits_collected) & 0x3fu];
      }
   }
   if (bits_collected > 0) { // Any trailing bits that are missing.
      assert(bits_collected < 6);
      accumulator <<= 6 - bits_collected;
      retval[outpos++] = b64_table[accumulator & 0x3fu];
   }
   assert(outpos >= (retval.size() - 2));
   assert(outpos <= retval.size());
   return retval;
}

size_t read_file()
{
	FILE* hFile=NULL;
	size_t fileSize(0),len(0),buffer_size(0);

	//opening the file
	hFile = fopen(FILENAME,"rb");
	if (hFile == NULL)
		throw "File Does not exist.";

	//get file size
	fseek(hFile,0,SEEK_END);
	fileSize = ftell(hFile);
	fseek(hFile,0,SEEK_SET);
	buffer_size += fileSize;

	//Checking file size
	if(fileSize > 1*1024)
	{}

	int no_of_rows = fileSize/SEND_BUF_SIZE + 1;
	int read(0);
	fileBuf = new char[ADD_SIZE + no_of_rows + 1][CHARS];	//Extra row for our special character to be used in conditional statements,here ""
											// ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
	buffer_size += ADD_SIZE;

	strcpy(fileBuf[len++],"To: " TO "\r\n");
	strcpy(fileBuf[len++],"From: " FROM "\r\n");
	strcpy(fileBuf[len++],"Subject: SMTP TLS example message\r\n");
	strcpy(fileBuf[len++],"Content-Type: application/x-msdownload; name=\"" FILENAME "\"\r\n");
	strcpy(fileBuf[len++],"Content-Transfer-Encoding: base64\r\n");
	strcpy(fileBuf[len++],"Content-Disposition: attachment; filename=\"" FILENAME "\"\r\n");
	strcpy(fileBuf[len++],"\r\n");

	char* temp_buf = new char[SEND_BUF_SIZE + 4];	//taking extra size of 4 bytes
	std::string encodedStr, temp_buf_str;
	
	for (; len < no_of_rows + ADD_SIZE; ++len)
	{
		read = fread(temp_buf,sizeof(char),SEND_BUF_SIZE,hFile);
		temp_buf[read] ='\0';
		temp_buf_str = std::string(temp_buf);
		encodedStr = base64_encode(temp_buf_str);
		encodedStr += "\r\n";
		memcpy(fileBuf[len],encodedStr.c_str(),encodedStr.size()+1);
	}
	strcpy(fileBuf[len],"");
	return buffer_size;
}

static size_t fileBuf_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
	struct fileBuf_upload_status *upload_ctx = (struct fileBuf_upload_status *)userp;
	const char *fdata;

	if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) 
	{
		return 0;
	}

	fdata = fileBuf[upload_ctx->lines_read];

	if(strcmp(fdata,"")) 
	{
		size_t len = strlen(fdata);
		memcpy(ptr, fdata, len);
		upload_ctx->lines_read++;
		return len;
	}
	return 0;
}

int main()
{
	  CURL *curl;
	  CURLcode res = CURLE_OK;
	  struct curl_slist *recipients = NULL;
	  struct fileBuf_upload_status file_upload_ctx;
	  size_t file_size(0);

	  file_upload_ctx.lines_read = 0;

	  curl = curl_easy_init();
	  file_size = read_file();

	  if(curl) 
	  {
		curl_easy_setopt(curl, CURLOPT_USERNAME, "xxxx");
		curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxx");
		curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
		curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
		curl_easy_setopt(curl, CURLOPT_CAINFO, "google.pem");
		curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
		recipients = curl_slist_append(recipients, TO);
		curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);

		curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_size); 
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, fileBuf_source);
		curl_easy_setopt(curl, CURLOPT_READDATA, &file_upload_ctx);
		curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
	  }
	  while(true)
	  {
		  res = curl_easy_perform(curl);
		  if(res == CURLE_OK)
		  {
			  curl_easy_cleanup(curl);
			  delete[] fileBuf;
			  break;
		  }
		  Sleep(delay);
	  }

          system("pause");
          return 0;
}


Any suggestion??
Posted
Updated 4-Feb-14 21:08pm
v3
Comments
Jochen Arndt 4-Feb-14 7:07am    
The size send by the SMPT SIZE command is very big ('SIZE=22322250707370015'). You should check where this large number comes from.
ansh_kumar 4-Feb-14 7:10am    
Thats what I'm searching, but no result till now...
In debug version it's only 31 (I guess)...
Jochen Arndt 4-Feb-14 7:41am    
You should check the value passed to curl with debug and release builds (e.g. by printing it out). The code looks good. But you may have a buffer overrun that overwrites the value.
ansh_kumar 5-Feb-14 3:07am    
Yes you were right buffer was overrunning, I've corrected it.

As mentionned in solution 2, there are some memory leaks. Any memory allocated by new or new[] should be released by delete (or delete[] respectively.

And also inspired by that solution, you might have a difference between the reported file size and the actual required size like the exact handling of new lines and other spaces or partial bloc of data.

It should be relatively easy to add some validation checks for debugging purpose. For exemple, you can count the number of byte written in the file or a block and compare with expected or allocated value.

Before each appending, you can validate that there is still enough room.

You can then use a debugger and set breakpoints that will trigger when you are about to overflow a buffer.

You can also try to add some extra space to one or more of the buffer and check if the problem still occurs. If not, then maybe, your estimated size was too small. You should then verify that computed values are safe in all cases.
 
Share this answer
 
Check the results of fread, fseek, and ftell for errors - which can ruin your file size estimates.

Also, you have a memory leak.
CSS
char* temp_buf = new char[SEND_BUF_SIZE + 4];   //taking extra size of 4 bytes
 
Share this answer
 
Comments
CHill60 4-Feb-14 16:32pm    
Could you explain why that line causes a memory leak?
Matt T Heffron 4-Feb-14 20:54pm    
You never delete it!
CHill60 5-Feb-14 4:43am    
D'oh! I'm not the OP but I just couldn't see that last night for love nor money. Thank You!
Without seeing your code we can give little help. However you should have a look to the classical Newcomer's article: "Surviving the Release Version"[^].
 
Share this answer
 
Comments
ansh_kumar 4-Feb-14 6:28am    
Wait I'm editing the question.
I've finally found a working code and found where the buffer was overflowing but I still need some explanation how it's happening.
First my correction to the code:

In function read_file()
C++
...
buffer_size += fileSize;
...

buffer_size += ADD_SIZE;
...

	strcpy(fileBuf[len++],"To: " TO "\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;	// 1 for \0
	strcpy(fileBuf[len++],"From: " FROM "\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Subject: SMTP TLS example message\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Type: application/x-msdownload; name=\"" FILENAME "\"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Transfer-Encoding: base64\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Disposition: attachment; filename=\"" FILENAME "\"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
...
	for (; len < no_of_rows + ADD_SIZE; ++len)
	{
                ...
		buffer_size += encodedStr.size() + 1;	// 1 for \0
	}
...

delete[] temp_buf;


And in the main() function:
C++
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_size);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size); 


Now the code is working well but I'm not able to get why CURLOPT_INFILESIZE_LARGE is changed to CURLOPT_INFILESIZE ???
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900