Created
May 27, 2023 23:58
-
-
Save puppis42/a122878000d0f76b4ab7d9fed434723f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <curl/curl.h> | |
#include <string> | |
#include <iostream> | |
#include <vector> | |
#include <fstream> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
using namespace std; | |
#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 | |
static const char* payload_text[] = { | |
"Subject: SMTPS Example\r\n", | |
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n", | |
"User-Agent: My eMail Client\r\n", | |
"MIME-Version: 1.0\r\n", | |
"Content-Type: multipart/mixed;\r\n", | |
" boundary=\"------------030203080101020302070708\"\r\n", | |
"\r\nThis is a multi-part message in MIME format.\r\n", | |
"--------------030203080101020302070708\r\n", | |
"Content-Type: text/html; charset=utf-8; format=flowed\r\n", /* text/plain : NO HTML | text/html : HTML */ | |
"Content-Transfer-Encoding: 7bit\r\n", | |
"\r\n", /* empty line to divide headers from body, see RFC5322 */ | |
"<h1>The body of the message starts here.</h1>\r\n", | |
"<img height='300' weight='500' src='<url>'/>\r\n", | |
"\r\n", | |
"It could be a lot of lines, could be MIME encoded, whatever.\r\n", | |
"Check RFC5322.\r\n\r\n", | |
"--------------030203080101020302070708\r\n", | |
"Content-Type: image/png; charset=utf-8; format=flowed\r\n", //First edit image/gif | |
"Content-Transfer-Encoding: base64\r\n", | |
"Content-Disposition: attachment;\r\n", | |
" filename=\"abc.png\"\r\n", | |
"\r\n", | |
//Base64 Data | |
"[FILE-DATA-TO-BASE64]\r\n", | |
"--------------030203080101020302070708--\r\n", | |
NULL | |
}; | |
//FILE TO BASE64 | |
const char* base64_chars{ | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
"abcdefghijklmnopqrstuvwxyz" | |
"0123456789+/" }; | |
string base64_encode(unsigned const char* input, unsigned const int len) { | |
string ret; | |
size_t i = 0; | |
unsigned char bytes[3]; | |
unsigned char sextets[4]; | |
while (i <= (len - 3)) { | |
bytes[0] = *(input++); | |
bytes[1] = *(input++); | |
bytes[2] = *(input++); | |
sextets[0] = (bytes[0] & 0xfc) >> 2; // Cuts last two bits off of first byte | |
sextets[1] = ((bytes[0] & 0x03) << 4) + ((bytes[1] & 0xf0) >> 4); // Takes last two bits from first byte and adds it to first 4 bits of 2nd byte | |
sextets[2] = ((bytes[1] & 0x0f) << 2) + ((bytes[2] & 0xc0) >> 6); // Takes last 4 bits of 2nd byte and adds it to first 2 bits of third byte | |
sextets[3] = bytes[2] & 0x3f; // takes last 6 bits of third byte | |
for (size_t j = 0; j < 4; ++j) { | |
ret += base64_chars[sextets[j]]; | |
} | |
i += 3; // increases to go to third byte | |
} | |
if (i != len) { | |
size_t k = 0; | |
size_t j = len - i; // Find index of last byte | |
while (k < j) { // Sets first bytes | |
bytes[k] = *(input++); | |
++k; | |
} | |
while (j < 3) { // Set last bytes to 0x00 | |
bytes[j] = '\0'; | |
++j; | |
} | |
sextets[0] = (bytes[0] & 0xfc) >> 2; // Cuts last two bits off of first byte | |
sextets[1] = ((bytes[0] & 0x03) << 4) + ((bytes[1] & 0xf0) >> 4); // Takes last two bits from first byte and adds it to first 4 bits of 2nd byte | |
sextets[2] = ((bytes[1] & 0x0f) << 2) + ((bytes[2] & 0xc0) >> 6); // Takes last 4 bits of 2nd byte and adds it to first 2 bits of third byte | |
// No last one is needed, because if there were 4, then (i == len) == true | |
for (j = 0; j < (len - i) + 1; ++j) { // Gets sextets that include data | |
ret += base64_chars[sextets[j]]; // Appends them to string | |
} | |
while ((j++) < 4) // Appends remaining ='s | |
ret += '='; | |
} | |
return ret; | |
} | |
string base64_encode_image(const string& path) { | |
vector<char> temp; | |
ifstream infile; | |
infile.open(path, ios::binary); // Open file in binary mode | |
if (infile.is_open()) { | |
while (!infile.eof()) { | |
char c = (char)infile.get(); | |
temp.push_back(c); | |
} | |
infile.close(); | |
} | |
else return "File could not be opened"; | |
string ret(temp.begin(), temp.end() - 1); | |
ret = base64_encode((unsigned const char*)ret.c_str(), ret.size()); | |
return ret; | |
} | |
//SEND MAIL FUNCTION(S) | |
struct WriteThis { | |
int counter; | |
}; | |
static size_t read_callback(void* ptr, size_t size, size_t nmemb, void* userp) | |
{ | |
struct WriteThis* pooh = (struct WriteThis*)userp; | |
const char* data; | |
if (size * nmemb < 1) | |
return 0; | |
data = payload_text[pooh->counter]; | |
if (data) { | |
size_t len = strlen(data); | |
memcpy(ptr, data, len); | |
pooh->counter++; /* advance pointer */ | |
return len; | |
} | |
return 0; /* no more data left to deliver */ | |
} | |
static struct timeval tvnow(void) | |
{ | |
/* | |
** time() returns the value of time in seconds since the Epoch. | |
*/ | |
struct timeval now; | |
now.tv_sec = (long)time(NULL); | |
now.tv_usec = 0; | |
return now; | |
} | |
static long tvdiff(struct timeval newer, struct timeval older) | |
{ | |
return (newer.tv_sec - older.tv_sec) * 1000 + | |
(newer.tv_usec - older.tv_usec) / 1000; | |
} | |
int sendMail(string userName, string password, const char* recipient, string smtpServer, string smtpPort) { | |
CURL* curl; | |
CURLM* mcurl; | |
int still_running = 1; | |
struct timeval mp_start; | |
struct WriteThis pooh; | |
struct curl_slist* rcpt_list = NULL; | |
pooh.counter = 0; | |
curl_global_init(CURL_GLOBAL_DEFAULT); | |
curl = curl_easy_init(); | |
if (!curl) | |
return 1; | |
mcurl = curl_multi_init(); | |
if (!mcurl) | |
return 2; | |
rcpt_list = curl_slist_append(rcpt_list, recipient); | |
/* more addresses can be added here | |
rcpt_list = curl_slist_append(rcpt_list, "<[email protected]>"); | |
*/ | |
curl_easy_setopt(curl, CURLOPT_URL, ("smtp://" + smtpServer + ":" + smtpPort).c_str()); | |
curl_easy_setopt(curl, CURLOPT_USERNAME, userName.c_str()); | |
curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); | |
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); | |
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, userName.c_str()); | |
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt_list); | |
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); | |
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); | |
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); | |
curl_easy_setopt(curl, CURLOPT_READDATA, &pooh); | |
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); | |
curl_easy_setopt(curl, CURLOPT_SSLVERSION, 0L); | |
curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); | |
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); | |
curl_multi_add_handle(mcurl, curl); | |
mp_start = tvnow(); | |
/* we start some action by calling perform right away */ | |
curl_multi_perform(mcurl, &still_running); | |
while (still_running) { | |
struct timeval timeout; | |
int rc; /* select() return code */ | |
fd_set fdread; | |
fd_set fdwrite; | |
fd_set fdexcep; | |
int maxfd = -1; | |
long curl_timeo = -1; | |
FD_ZERO(&fdread); | |
FD_ZERO(&fdwrite); | |
FD_ZERO(&fdexcep); | |
/* set a suitable timeout to play around with */ | |
timeout.tv_sec = 1; | |
timeout.tv_usec = 0; | |
curl_multi_timeout(mcurl, &curl_timeo); | |
if (curl_timeo >= 0) { | |
timeout.tv_sec = curl_timeo / 1000; | |
if (timeout.tv_sec > 1) | |
timeout.tv_sec = 1; | |
else | |
timeout.tv_usec = (curl_timeo % 1000) * 1000; | |
} | |
/* get file descriptors from the transfers */ | |
curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd); | |
/* In a real-world program you OF COURSE check the return code of the | |
function calls. On success, the value of maxfd is guaranteed to be | |
greater or equal than -1. We call select(maxfd + 1, ...), specially in | |
case of (maxfd == -1), we call select(0, ...), which is basically equal | |
to sleep. */ | |
rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); | |
if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) { | |
fprintf(stderr, "ABORTING TEST, since it seems " | |
"that it would have run forever.\n"); | |
break; | |
return 101; | |
} | |
switch (rc) { | |
case -1: | |
/* select error */ | |
break; | |
return 200; | |
case 0: /* timeout */ | |
default: /* action */ | |
curl_multi_perform(mcurl, &still_running); | |
break; | |
} | |
} | |
curl_slist_free_all(rcpt_list); | |
curl_multi_remove_handle(mcurl, curl); | |
curl_multi_cleanup(mcurl); | |
curl_easy_cleanup(curl); | |
curl_global_cleanup(); | |
} | |
int main(void) | |
{ | |
string s = base64_encode_image("tst.png"); | |
payload_text[23] = s.c_str(), "\r\n"; | |
int res = sendMail("<mail-addr>", "<password>", | |
"<mail-addr>", "smtp.gmail.com", "587"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment