| 1 | /*
 | 
|---|
| 2 |     This file is part of libquickmail.
 | 
|---|
| 3 | 
 | 
|---|
| 4 |     libquickmail is free software: you can redistribute it and/or modify
 | 
|---|
| 5 |     it under the terms of the GNU General Public License as published by
 | 
|---|
| 6 |     the Free Software Foundation, either version 3 of the License, or
 | 
|---|
| 7 |     (at your option) any later version.
 | 
|---|
| 8 | 
 | 
|---|
| 9 |     libquickmail is distributed in the hope that it will be useful,
 | 
|---|
| 10 |     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 11 |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 12 |     GNU General Public License for more details.
 | 
|---|
| 13 | 
 | 
|---|
| 14 |     You should have received a copy of the GNU General Public License
 | 
|---|
| 15 |     along with libquickmail.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 16 | */
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #if defined(_WIN32) && defined(DLL_EXPORT) && !defined(BUILD_QUICKMAIL_DLL)
 | 
|---|
| 19 | #define BUILD_QUICKMAIL_DLL
 | 
|---|
| 20 | #endif
 | 
|---|
| 21 | #include "quickmail.h"
 | 
|---|
| 22 | #include <stdlib.h>
 | 
|---|
| 23 | #include <stdio.h>
 | 
|---|
| 24 | #include <string.h>
 | 
|---|
| 25 | #include <time.h>
 | 
|---|
| 26 | #ifndef _WIN32
 | 
|---|
| 27 | #include <unistd.h>
 | 
|---|
| 28 | #endif
 | 
|---|
| 29 | #if _MSC_VER
 | 
|---|
| 30 | #define snprintf _snprintf
 | 
|---|
| 31 | #define strdup _strdup
 | 
|---|
| 32 | #endif
 | 
|---|
| 33 | #ifndef NOCURL
 | 
|---|
| 34 | #if (defined(STATIC) || defined(BUILD_QUICKMAIL_STATIC)) && !defined(CURL_STATICLIB)
 | 
|---|
| 35 | #define CURL_STATICLIB
 | 
|---|
| 36 | #endif
 | 
|---|
| 37 | #include <curl/curl.h>
 | 
|---|
| 38 | #else
 | 
|---|
| 39 | #include "smtpsocket.h"
 | 
|---|
| 40 | #endif
 | 
|---|
| 41 | 
 | 
|---|
| 42 | #define LIBQUICKMAIL_VERSION_MAJOR 0
 | 
|---|
| 43 | #define LIBQUICKMAIL_VERSION_MINOR 1
 | 
|---|
| 44 | #define LIBQUICKMAIL_VERSION_MICRO 18
 | 
|---|
| 45 | 
 | 
|---|
| 46 | #define VERSION_STRINGIZE_(major, minor, micro) #major"."#minor"."#micro
 | 
|---|
| 47 | #define VERSION_STRINGIZE(major, minor, micro) VERSION_STRINGIZE_(major, minor, micro)
 | 
|---|
| 48 | 
 | 
|---|
| 49 | #define LIBQUICKMAIL_VERSION VERSION_STRINGIZE(LIBQUICKMAIL_VERSION_MAJOR,LIBQUICKMAIL_VERSION_MINOR,LIBQUICKMAIL_VERSION_MICRO)
 | 
|---|
| 50 | 
 | 
|---|
| 51 | #define NEWLINE "\r\n"
 | 
|---|
| 52 | #define NEWLINELENGTH 2
 | 
|---|
| 53 | //#define NEWLINE "\n"
 | 
|---|
| 54 | //#define NEWLINELENGTH 1
 | 
|---|
| 55 | 
 | 
|---|
| 56 | #define MIME_LINE_WIDTH 72
 | 
|---|
| 57 | #define BODY_BUFFER_SIZE 256
 | 
|---|
| 58 | 
 | 
|---|
| 59 | //definitions of the differen stages of generating the message data
 | 
|---|
| 60 | #define MAILPART_INITIALIZE 0
 | 
|---|
| 61 | #define MAILPART_HEADER     1
 | 
|---|
| 62 | #define MAILPART_BODY       2
 | 
|---|
| 63 | #define MAILPART_BODY_DONE  3
 | 
|---|
| 64 | #define MAILPART_ATTACHMENT 4
 | 
|---|
| 65 | #define MAILPART_END        5
 | 
|---|
| 66 | #define MAILPART_DONE       6
 | 
|---|
| 67 | 
 | 
|---|
| 68 | static const char* default_mime_type = "text/plain";
 | 
|---|
| 69 | 
 | 
|---|
| 70 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 71 | 
 | 
|---|
| 72 | #define DEBUG_ERROR(errmsg)
 | 
|---|
| 73 | static const char* ERRMSG_MEMORY_ALLOCATION_ERROR = "Memory allocation error";
 | 
|---|
| 74 | 
 | 
|---|
| 75 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 76 | 
 | 
|---|
| 77 | char* randomize_zeros (char* data)
 | 
|---|
| 78 | {
 | 
|---|
| 79 |   //replace all 0s with random digits
 | 
|---|
| 80 |   char* p = data;
 | 
|---|
| 81 |   while (*p) {
 | 
|---|
| 82 |     if (*p == '0')
 | 
|---|
| 83 |       *p = '0' + rand() % 10;
 | 
|---|
| 84 |     p++;
 | 
|---|
| 85 |   }
 | 
|---|
| 86 |   return data;
 | 
|---|
| 87 | }
 | 
|---|
| 88 | 
 | 
|---|
| 89 | char* str_append (char** data, const char* newdata)
 | 
|---|
| 90 | {
 | 
|---|
| 91 |   //append a string to the end of an existing string
 | 
|---|
| 92 |   char* p;
 | 
|---|
| 93 |   int len = (*data ? strlen(*data) : 0);
 | 
|---|
| 94 |   if ((p = (char*)realloc(*data, len + strlen(newdata) + 1)) == NULL) {
 | 
|---|
| 95 |     free(p);
 | 
|---|
| 96 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 97 |     return NULL;
 | 
|---|
| 98 |   }
 | 
|---|
| 99 |   *data = p;
 | 
|---|
| 100 |   strcpy(*data + len, newdata);
 | 
|---|
| 101 |   return *data;
 | 
|---|
| 102 | }
 | 
|---|
| 103 | 
 | 
|---|
| 104 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 105 | 
 | 
|---|
| 106 | struct email_info_struct {
 | 
|---|
| 107 |   int current;  //must be zet to 0
 | 
|---|
| 108 |   time_t timestamp;
 | 
|---|
| 109 |   char* from;
 | 
|---|
| 110 |   struct email_info_email_list_struct* to;
 | 
|---|
| 111 |   struct email_info_email_list_struct* cc;
 | 
|---|
| 112 |   struct email_info_email_list_struct* bcc;
 | 
|---|
| 113 |   char* subject;
 | 
|---|
| 114 |   char* header;
 | 
|---|
| 115 |   struct email_info_attachment_list_struct* bodylist;
 | 
|---|
| 116 |   struct email_info_attachment_list_struct* attachmentlist;
 | 
|---|
| 117 |   char* buf;
 | 
|---|
| 118 |   int buflen;
 | 
|---|
| 119 |   char* mime_boundary_body;
 | 
|---|
| 120 |   char* mime_boundary_part;
 | 
|---|
| 121 |   struct email_info_attachment_list_struct* current_attachment;
 | 
|---|
| 122 |   FILE* debuglog;
 | 
|---|
| 123 |   char dtable[64];
 | 
|---|
| 124 | };
 | 
|---|
| 125 | 
 | 
|---|
| 126 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 127 | 
 | 
|---|
| 128 | struct email_info_email_list_struct {
 | 
|---|
| 129 |   char* data;
 | 
|---|
| 130 |   struct email_info_email_list_struct* next;
 | 
|---|
| 131 | };
 | 
|---|
| 132 | 
 | 
|---|
| 133 | void email_info_string_list_add (struct email_info_email_list_struct** list, const char* data)
 | 
|---|
| 134 | {
 | 
|---|
| 135 |   struct email_info_email_list_struct** p = list;
 | 
|---|
| 136 |   while (*p)
 | 
|---|
| 137 |     p = &(*p)->next;
 | 
|---|
| 138 |   if ((*p = (struct email_info_email_list_struct*)malloc(sizeof(struct email_info_email_list_struct))) == NULL) {
 | 
|---|
| 139 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 140 |     return;
 | 
|---|
| 141 |   }
 | 
|---|
| 142 |   (*p)->data = (data ? strdup(data) : NULL);
 | 
|---|
| 143 |   (*p)->next = NULL;
 | 
|---|
| 144 | }
 | 
|---|
| 145 | 
 | 
|---|
| 146 | void email_info_string_list_free (struct email_info_email_list_struct** list)
 | 
|---|
| 147 | {
 | 
|---|
| 148 |   struct email_info_email_list_struct* p = *list;
 | 
|---|
| 149 |   struct email_info_email_list_struct* current;
 | 
|---|
| 150 |   while (p) {
 | 
|---|
| 151 |     current = p;
 | 
|---|
| 152 |     p = current->next;
 | 
|---|
| 153 |     free(current->data);
 | 
|---|
| 154 |     free(current);
 | 
|---|
| 155 |   }
 | 
|---|
| 156 |   *list = NULL;
 | 
|---|
| 157 | }
 | 
|---|
| 158 | 
 | 
|---|
| 159 | char* email_info_string_list_concatenate (struct email_info_email_list_struct* list)
 | 
|---|
| 160 | {
 | 
|---|
| 161 |   char* result = NULL;
 | 
|---|
| 162 |   struct email_info_email_list_struct* listentry = list;
 | 
|---|
| 163 |   while (listentry) {
 | 
|---|
| 164 |     if (listentry->data && *listentry->data) {
 | 
|---|
| 165 |       if (result)
 | 
|---|
| 166 |         str_append(&result, "," NEWLINE "\t");
 | 
|---|
| 167 |       str_append(&result, "<");
 | 
|---|
| 168 |       str_append(&result, listentry->data);
 | 
|---|
| 169 |       str_append(&result, ">");
 | 
|---|
| 170 |     }
 | 
|---|
| 171 |     listentry = listentry->next;
 | 
|---|
| 172 |   }
 | 
|---|
| 173 |   return result;
 | 
|---|
| 174 | }
 | 
|---|
| 175 | 
 | 
|---|
| 176 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 177 | 
 | 
|---|
| 178 | struct email_info_attachment_list_struct {
 | 
|---|
| 179 |   char* filename;
 | 
|---|
| 180 |   char* mimetype;
 | 
|---|
| 181 |   void* filedata;
 | 
|---|
| 182 |   void* handle;
 | 
|---|
| 183 |   quickmail_attachment_open_fn email_info_attachment_open;
 | 
|---|
| 184 |   quickmail_attachment_read_fn email_info_attachment_read;
 | 
|---|
| 185 |   quickmail_attachment_close_fn email_info_attachment_close;
 | 
|---|
| 186 |   quickmail_attachment_free_filedata_fn email_info_attachment_filedata_free;
 | 
|---|
| 187 |   struct email_info_attachment_list_struct* next;
 | 
|---|
| 188 | };
 | 
|---|
| 189 | 
 | 
|---|
| 190 | struct email_info_attachment_list_struct* email_info_attachment_list_add (struct email_info_attachment_list_struct** list, const char* filename, const char* mimetype, void* filedata, quickmail_attachment_open_fn email_info_attachment_open, quickmail_attachment_read_fn email_info_attachment_read, quickmail_attachment_close_fn email_info_attachment_close, quickmail_attachment_free_filedata_fn email_info_attachment_filedata_free)
 | 
|---|
| 191 | {
 | 
|---|
| 192 |   struct email_info_attachment_list_struct** p = list;
 | 
|---|
| 193 |   while (*p)
 | 
|---|
| 194 |     p = &(*p)->next;
 | 
|---|
| 195 |   if ((*p = (struct email_info_attachment_list_struct*)malloc(sizeof(struct email_info_attachment_list_struct))) == NULL) {
 | 
|---|
| 196 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 197 |     return NULL;
 | 
|---|
| 198 |   }
 | 
|---|
| 199 |   (*p)->filename = strdup(filename ? filename : "UNNAMED");
 | 
|---|
| 200 |   (*p)->mimetype = (mimetype ? strdup(mimetype) : NULL);
 | 
|---|
| 201 |   (*p)->filedata = filedata;
 | 
|---|
| 202 |   (*p)->handle = NULL;
 | 
|---|
| 203 |   (*p)->email_info_attachment_open = email_info_attachment_open;
 | 
|---|
| 204 |   (*p)->email_info_attachment_read = email_info_attachment_read;
 | 
|---|
| 205 |   (*p)->email_info_attachment_close = email_info_attachment_close;
 | 
|---|
| 206 |   (*p)->email_info_attachment_filedata_free = email_info_attachment_filedata_free;
 | 
|---|
| 207 |   (*p)->next = NULL;
 | 
|---|
| 208 |   return *p;
 | 
|---|
| 209 | }
 | 
|---|
| 210 | 
 | 
|---|
| 211 | void email_info_attachment_list_free_entry (struct email_info_attachment_list_struct* current)
 | 
|---|
| 212 | {
 | 
|---|
| 213 |   if (current->handle) {
 | 
|---|
| 214 |     if (current->email_info_attachment_close)
 | 
|---|
| 215 |       current->email_info_attachment_close(current->handle);
 | 
|---|
| 216 |     //else
 | 
|---|
| 217 |     //  free(current->handle);
 | 
|---|
| 218 |     current->handle = NULL;
 | 
|---|
| 219 |   }
 | 
|---|
| 220 |   if (current->filedata) {
 | 
|---|
| 221 |     if (current->email_info_attachment_filedata_free)
 | 
|---|
| 222 |       current->email_info_attachment_filedata_free(current->filedata);
 | 
|---|
| 223 |     else
 | 
|---|
| 224 |       free(current->filedata);
 | 
|---|
| 225 |   }
 | 
|---|
| 226 |   if (current->mimetype)
 | 
|---|
| 227 |     free(current->mimetype);
 | 
|---|
| 228 |   free(current->filename);
 | 
|---|
| 229 |   free(current);
 | 
|---|
| 230 | }
 | 
|---|
| 231 | 
 | 
|---|
| 232 | void email_info_attachment_list_free (struct email_info_attachment_list_struct** list)
 | 
|---|
| 233 | {
 | 
|---|
| 234 |   struct email_info_attachment_list_struct* p = *list;
 | 
|---|
| 235 |   struct email_info_attachment_list_struct* current;
 | 
|---|
| 236 |   while (p) {
 | 
|---|
| 237 |     current = p;
 | 
|---|
| 238 |     p = current->next;
 | 
|---|
| 239 |     email_info_attachment_list_free_entry(current);
 | 
|---|
| 240 |   }
 | 
|---|
| 241 |   *list = NULL;
 | 
|---|
| 242 | }
 | 
|---|
| 243 | 
 | 
|---|
| 244 | int email_info_attachment_list_delete (struct email_info_attachment_list_struct** list, const char* filename)
 | 
|---|
| 245 | {
 | 
|---|
| 246 |   struct email_info_attachment_list_struct** p = list;
 | 
|---|
| 247 |   while (*p) {
 | 
|---|
| 248 |     if (strcmp((*p)->filename, filename) == 0) {
 | 
|---|
| 249 |       struct email_info_attachment_list_struct* current = *p;
 | 
|---|
| 250 |       *p = current->next;
 | 
|---|
| 251 |       email_info_attachment_list_free_entry(current);
 | 
|---|
| 252 |       return 0;
 | 
|---|
| 253 |     }
 | 
|---|
| 254 |     p = &(*p)->next;
 | 
|---|
| 255 |   }
 | 
|---|
| 256 |   return -1;
 | 
|---|
| 257 | }
 | 
|---|
| 258 | 
 | 
|---|
| 259 | void email_info_attachment_list_close_handles (struct email_info_attachment_list_struct* list)
 | 
|---|
| 260 | {
 | 
|---|
| 261 |   struct email_info_attachment_list_struct* p = list;
 | 
|---|
| 262 |   while (p) {
 | 
|---|
| 263 |     if (p->handle) {
 | 
|---|
| 264 |       if (p->email_info_attachment_close)
 | 
|---|
| 265 |         p->email_info_attachment_close(p->handle);
 | 
|---|
| 266 |       //else
 | 
|---|
| 267 |       //  free(p->handle);
 | 
|---|
| 268 |       p->handle = NULL;
 | 
|---|
| 269 |     }
 | 
|---|
| 270 |     p = p->next;
 | 
|---|
| 271 |   }
 | 
|---|
| 272 | }
 | 
|---|
| 273 | 
 | 
|---|
| 274 | //dummy attachment functions
 | 
|---|
| 275 | 
 | 
|---|
| 276 | void* email_info_attachment_open_dummy (void* filedata)
 | 
|---|
| 277 | {
 | 
|---|
| 278 |   return &email_info_attachment_open_dummy;
 | 
|---|
| 279 | }
 | 
|---|
| 280 | 
 | 
|---|
| 281 | size_t email_info_attachment_read_dummy (void* handle, void* buf, size_t len)
 | 
|---|
| 282 | {
 | 
|---|
| 283 |   return 0;
 | 
|---|
| 284 | }
 | 
|---|
| 285 | 
 | 
|---|
| 286 | struct email_info_attachment_list_struct* email_info_attachment_list_add_dummy (struct email_info_attachment_list_struct** list, const char* filename, const char* mimetype)
 | 
|---|
| 287 | {
 | 
|---|
| 288 |   return email_info_attachment_list_add(list, filename, mimetype, NULL, email_info_attachment_open_dummy, email_info_attachment_read_dummy, NULL, NULL);
 | 
|---|
| 289 | }
 | 
|---|
| 290 | 
 | 
|---|
| 291 | //file attachment functions
 | 
|---|
| 292 | 
 | 
|---|
| 293 | void* email_info_attachment_open_file (void* filedata)
 | 
|---|
| 294 | {
 | 
|---|
| 295 |   return (void*)fopen((char*)filedata, "rb");
 | 
|---|
| 296 | }
 | 
|---|
| 297 | 
 | 
|---|
| 298 | size_t email_info_attachment_read_file (void* handle, void* buf, size_t len)
 | 
|---|
| 299 | {
 | 
|---|
| 300 |   return fread(buf, 1, len, (FILE*)handle);
 | 
|---|
| 301 | }
 | 
|---|
| 302 | 
 | 
|---|
| 303 | void email_info_attachment_close_file (void* handle)
 | 
|---|
| 304 | {
 | 
|---|
| 305 |   if (handle)
 | 
|---|
| 306 |     fclose((FILE*)handle);
 | 
|---|
| 307 | }
 | 
|---|
| 308 | 
 | 
|---|
| 309 | struct email_info_attachment_list_struct* email_info_attachment_list_add_file (struct email_info_attachment_list_struct** list, const char* path, const char* mimetype)
 | 
|---|
| 310 | {
 | 
|---|
| 311 |   //determine base filename
 | 
|---|
| 312 |   const char* basename = path + strlen(path);
 | 
|---|
| 313 |   while (basename != path) {
 | 
|---|
| 314 |     basename--;
 | 
|---|
| 315 |     if (*basename == '/'
 | 
|---|
| 316 | #ifdef _WIN32
 | 
|---|
| 317 |         || *basename == '\\' || *basename == ':'
 | 
|---|
| 318 | #endif
 | 
|---|
| 319 |     ) {
 | 
|---|
| 320 |       basename++;
 | 
|---|
| 321 |       break;
 | 
|---|
| 322 |     }
 | 
|---|
| 323 |   }
 | 
|---|
| 324 |   return email_info_attachment_list_add(list, basename, mimetype, (void*)strdup(path), email_info_attachment_open_file, email_info_attachment_read_file, email_info_attachment_close_file, NULL);
 | 
|---|
| 325 | }
 | 
|---|
| 326 | 
 | 
|---|
| 327 | //memory attachment functions
 | 
|---|
| 328 | 
 | 
|---|
| 329 | struct email_info_attachment_memory_filedata_struct {
 | 
|---|
| 330 |   char* data;
 | 
|---|
| 331 |   size_t datalen;
 | 
|---|
| 332 |   int mustfree;
 | 
|---|
| 333 | };
 | 
|---|
| 334 | 
 | 
|---|
| 335 | struct email_info_attachment_memory_handle_struct {
 | 
|---|
| 336 |   const char* data;
 | 
|---|
| 337 |   size_t datalen;
 | 
|---|
| 338 |   size_t pos;
 | 
|---|
| 339 | };
 | 
|---|
| 340 | 
 | 
|---|
| 341 | void* email_info_attachment_open_memory (void* filedata)
 | 
|---|
| 342 | {
 | 
|---|
| 343 |   struct email_info_attachment_memory_filedata_struct* data;
 | 
|---|
| 344 |   struct email_info_attachment_memory_handle_struct* result;
 | 
|---|
| 345 |   data = ((struct email_info_attachment_memory_filedata_struct*)filedata);
 | 
|---|
| 346 |   if (!data->data)
 | 
|---|
| 347 |     return NULL;
 | 
|---|
| 348 |   if ((result = (struct email_info_attachment_memory_handle_struct*)malloc(sizeof(struct email_info_attachment_memory_handle_struct))) == NULL) {
 | 
|---|
| 349 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 350 |     return NULL;
 | 
|---|
| 351 |   }
 | 
|---|
| 352 |   result->data = data->data;
 | 
|---|
| 353 |   result->datalen = data->datalen;
 | 
|---|
| 354 |   result->pos = 0;
 | 
|---|
| 355 |   return result;
 | 
|---|
| 356 | }
 | 
|---|
| 357 | 
 | 
|---|
| 358 | size_t email_info_attachment_read_memory (void* handle, void* buf, size_t len)
 | 
|---|
| 359 | {
 | 
|---|
| 360 |   struct email_info_attachment_memory_handle_struct* h = (struct email_info_attachment_memory_handle_struct*)handle;
 | 
|---|
| 361 |   size_t n = (h->pos + len <= h->datalen ? len : h->datalen - h->pos);
 | 
|---|
| 362 |   memcpy(buf, h->data + h->pos, n);
 | 
|---|
| 363 |   h->pos += n;
 | 
|---|
| 364 |   return n;
 | 
|---|
| 365 | }
 | 
|---|
| 366 | 
 | 
|---|
| 367 | void email_info_attachment_close_memory (void* handle)
 | 
|---|
| 368 | {
 | 
|---|
| 369 |   if (handle)
 | 
|---|
| 370 |     free(handle);
 | 
|---|
| 371 | }
 | 
|---|
| 372 | 
 | 
|---|
| 373 | void email_info_attachment_filedata_free_memory (void* filedata)
 | 
|---|
| 374 | {
 | 
|---|
| 375 |   struct email_info_attachment_memory_filedata_struct* data = ((struct email_info_attachment_memory_filedata_struct*)filedata);
 | 
|---|
| 376 |   if (data) {
 | 
|---|
| 377 |     if (data->mustfree)
 | 
|---|
| 378 |       free(data->data);
 | 
|---|
| 379 |     free(data);
 | 
|---|
| 380 |   }
 | 
|---|
| 381 | }
 | 
|---|
| 382 | 
 | 
|---|
| 383 | struct email_info_attachment_list_struct* email_info_attachment_list_add_memory (struct email_info_attachment_list_struct** list, const char* filename, const char* mimetype, char* data, size_t datalen, int mustfree)
 | 
|---|
| 384 | {
 | 
|---|
| 385 |   struct email_info_attachment_memory_filedata_struct* filedata;
 | 
|---|
| 386 |   if ((filedata = (struct email_info_attachment_memory_filedata_struct*)malloc(sizeof(struct email_info_attachment_memory_filedata_struct))) == NULL) {
 | 
|---|
| 387 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 388 |     return NULL;
 | 
|---|
| 389 |   }
 | 
|---|
| 390 |   filedata->data = data;
 | 
|---|
| 391 |   filedata->datalen = datalen;
 | 
|---|
| 392 |   filedata->mustfree = mustfree;
 | 
|---|
| 393 |   return email_info_attachment_list_add(list, filename, mimetype, filedata, email_info_attachment_open_memory, email_info_attachment_read_memory, email_info_attachment_close_memory, email_info_attachment_filedata_free_memory);
 | 
|---|
| 394 | }
 | 
|---|
| 395 | 
 | 
|---|
| 396 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 397 | 
 | 
|---|
| 398 | DLL_EXPORT_LIBQUICKMAIL const char* quickmail_get_version ()
 | 
|---|
| 399 | {
 | 
|---|
| 400 |   return VERSION_STRINGIZE(LIBQUICKMAIL_VERSION_MAJOR, LIBQUICKMAIL_VERSION_MINOR, LIBQUICKMAIL_VERSION_MICRO)
 | 
|---|
| 401 | #if defined(NOCURL)
 | 
|---|
| 402 |     "-light"
 | 
|---|
| 403 | #endif
 | 
|---|
| 404 |   ;
 | 
|---|
| 405 | }
 | 
|---|
| 406 | 
 | 
|---|
| 407 | DLL_EXPORT_LIBQUICKMAIL int quickmail_initialize ()
 | 
|---|
| 408 | {
 | 
|---|
| 409 | #if defined(NOCURL) && defined(_WIN32)
 | 
|---|
| 410 |   static WSADATA wsaData;
 | 
|---|
| 411 |   int wsaerr = WSAStartup(MAKEWORD(1, 0), &wsaData);
 | 
|---|
| 412 |   if (wsaerr)
 | 
|---|
| 413 |     return -1;
 | 
|---|
| 414 |   atexit((void(*)())WSACleanup);
 | 
|---|
| 415 | #endif
 | 
|---|
| 416 |   return 0;
 | 
|---|
| 417 | }
 | 
|---|
| 418 | 
 | 
|---|
| 419 | DLL_EXPORT_LIBQUICKMAIL quickmail quickmail_create (const char* from, const char* subject)
 | 
|---|
| 420 | {
 | 
|---|
| 421 |   int i;
 | 
|---|
| 422 |   struct email_info_struct* mailobj;
 | 
|---|
| 423 |   if ((mailobj = (struct email_info_struct*)malloc(sizeof(struct email_info_struct))) == NULL) {
 | 
|---|
| 424 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 425 |     return NULL;
 | 
|---|
| 426 |   }
 | 
|---|
| 427 |   mailobj->current = 0;
 | 
|---|
| 428 |   mailobj->timestamp = time(NULL);
 | 
|---|
| 429 |   mailobj->from = (from ? strdup(from) : NULL);
 | 
|---|
| 430 |   mailobj->to = NULL;
 | 
|---|
| 431 |   mailobj->cc = NULL;
 | 
|---|
| 432 |   mailobj->bcc = NULL;
 | 
|---|
| 433 |   mailobj->subject = (subject ? strdup(subject) : NULL);
 | 
|---|
| 434 |   mailobj->header = NULL;
 | 
|---|
| 435 |   mailobj->bodylist = NULL;
 | 
|---|
| 436 |   mailobj->attachmentlist = NULL;
 | 
|---|
| 437 |   mailobj->buf = NULL;
 | 
|---|
| 438 |   mailobj->buflen = 0;
 | 
|---|
| 439 |   mailobj->mime_boundary_body = NULL;
 | 
|---|
| 440 |   mailobj->mime_boundary_part = NULL;
 | 
|---|
| 441 |   mailobj->current_attachment = NULL;
 | 
|---|
| 442 |   mailobj->debuglog = NULL;
 | 
|---|
| 443 |   for (i = 0; i < 26; i++) {
 | 
|---|
| 444 |     mailobj->dtable[i] = (char)('A' + i);
 | 
|---|
| 445 |     mailobj->dtable[26 + i] = (char)('a' + i);
 | 
|---|
| 446 |   }
 | 
|---|
| 447 |   for (i = 0; i < 10; i++) {
 | 
|---|
| 448 |     mailobj->dtable[52 + i] = (char)('0' + i);
 | 
|---|
| 449 |   }
 | 
|---|
| 450 |   mailobj->dtable[62] = '+';
 | 
|---|
| 451 |   mailobj->dtable[63] = '/';
 | 
|---|
| 452 |   srand(time(NULL));
 | 
|---|
| 453 |   return mailobj;
 | 
|---|
| 454 | }
 | 
|---|
| 455 | 
 | 
|---|
| 456 | DLL_EXPORT_LIBQUICKMAIL void quickmail_destroy (quickmail mailobj)
 | 
|---|
| 457 | {
 | 
|---|
| 458 |   free(mailobj->from);
 | 
|---|
| 459 |   email_info_string_list_free(&mailobj->to);
 | 
|---|
| 460 |   email_info_string_list_free(&mailobj->cc);
 | 
|---|
| 461 |   email_info_string_list_free(&mailobj->bcc);
 | 
|---|
| 462 |   free(mailobj->subject);
 | 
|---|
| 463 |   free(mailobj->header);
 | 
|---|
| 464 |   email_info_attachment_list_free(&mailobj->bodylist);
 | 
|---|
| 465 |   email_info_attachment_list_free(&mailobj->attachmentlist);
 | 
|---|
| 466 |   free(mailobj->buf);
 | 
|---|
| 467 |   free(mailobj->mime_boundary_body);
 | 
|---|
| 468 |   free(mailobj->mime_boundary_part);
 | 
|---|
| 469 |   free(mailobj);
 | 
|---|
| 470 | }
 | 
|---|
| 471 | 
 | 
|---|
| 472 | DLL_EXPORT_LIBQUICKMAIL void quickmail_set_from (quickmail mailobj, const char* from)
 | 
|---|
| 473 | {
 | 
|---|
| 474 |   free(mailobj->from);
 | 
|---|
| 475 |   mailobj->from = strdup(from);
 | 
|---|
| 476 | }
 | 
|---|
| 477 | 
 | 
|---|
| 478 | DLL_EXPORT_LIBQUICKMAIL const char* quickmail_get_from (quickmail mailobj)
 | 
|---|
| 479 | {
 | 
|---|
| 480 |   return mailobj->from;
 | 
|---|
| 481 | }
 | 
|---|
| 482 | 
 | 
|---|
| 483 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_to (quickmail mailobj, const char* email)
 | 
|---|
| 484 | {
 | 
|---|
| 485 |   email_info_string_list_add(&mailobj->to, email);
 | 
|---|
| 486 | }
 | 
|---|
| 487 | 
 | 
|---|
| 488 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_cc (quickmail mailobj, const char* email)
 | 
|---|
| 489 | {
 | 
|---|
| 490 |   email_info_string_list_add(&mailobj->cc, email);
 | 
|---|
| 491 | }
 | 
|---|
| 492 | 
 | 
|---|
| 493 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_bcc (quickmail mailobj, const char* email)
 | 
|---|
| 494 | {
 | 
|---|
| 495 |   email_info_string_list_add(&mailobj->bcc, email);
 | 
|---|
| 496 | }
 | 
|---|
| 497 | 
 | 
|---|
| 498 | DLL_EXPORT_LIBQUICKMAIL void quickmail_set_subject (quickmail mailobj, const char* subject)
 | 
|---|
| 499 | {
 | 
|---|
| 500 |   free(mailobj->subject);
 | 
|---|
| 501 |   mailobj->subject = (subject ? strdup(subject) : NULL);
 | 
|---|
| 502 | }
 | 
|---|
| 503 | 
 | 
|---|
| 504 | DLL_EXPORT_LIBQUICKMAIL const char* quickmail_get_subject (quickmail mailobj)
 | 
|---|
| 505 | {
 | 
|---|
| 506 |   return mailobj->subject;
 | 
|---|
| 507 | }
 | 
|---|
| 508 | 
 | 
|---|
| 509 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_header (quickmail mailobj, const char* headerline)
 | 
|---|
| 510 | {
 | 
|---|
| 511 |   str_append(&mailobj->header, headerline);
 | 
|---|
| 512 |   str_append(&mailobj->header, NEWLINE);
 | 
|---|
| 513 | }
 | 
|---|
| 514 | 
 | 
|---|
| 515 | DLL_EXPORT_LIBQUICKMAIL void quickmail_set_body (quickmail mailobj, const char* body)
 | 
|---|
| 516 | {
 | 
|---|
| 517 |   email_info_attachment_list_free(&mailobj->bodylist);
 | 
|---|
| 518 |   if (body)
 | 
|---|
| 519 |     email_info_attachment_list_add_memory(&mailobj->bodylist, default_mime_type, default_mime_type, strdup(body), strlen(body), 1);
 | 
|---|
| 520 | }
 | 
|---|
| 521 | 
 | 
|---|
| 522 | DLL_EXPORT_LIBQUICKMAIL char* quickmail_get_body (quickmail mailobj)
 | 
|---|
| 523 | {
 | 
|---|
| 524 |   size_t n;
 | 
|---|
| 525 |   char* p;
 | 
|---|
| 526 |   char* result = NULL;
 | 
|---|
| 527 |   size_t resultlen = 0;
 | 
|---|
| 528 |   if (mailobj->bodylist && (mailobj->bodylist->handle = mailobj->bodylist->email_info_attachment_open(mailobj->bodylist->filedata)) != NULL) {
 | 
|---|
| 529 |     do {
 | 
|---|
| 530 |       if ((p = (char*)realloc(result, resultlen + BODY_BUFFER_SIZE)) == NULL) {
 | 
|---|
| 531 |         free(result);
 | 
|---|
| 532 |         DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 533 |         break;
 | 
|---|
| 534 |       }
 | 
|---|
| 535 |       result = p;
 | 
|---|
| 536 |       if ((n = mailobj->bodylist->email_info_attachment_read(mailobj->bodylist->handle, result + resultlen, BODY_BUFFER_SIZE)) > 0)
 | 
|---|
| 537 |         resultlen += n;
 | 
|---|
| 538 |     } while (n > 0);
 | 
|---|
| 539 |     if (mailobj->bodylist->email_info_attachment_close)
 | 
|---|
| 540 |       mailobj->bodylist->email_info_attachment_close(mailobj->bodylist->handle);
 | 
|---|
| 541 |     //else
 | 
|---|
| 542 |     //  free(mailobj->bodylist->handle);
 | 
|---|
| 543 |     mailobj->bodylist->handle = NULL;
 | 
|---|
| 544 |   }
 | 
|---|
| 545 |   return result;
 | 
|---|
| 546 | }
 | 
|---|
| 547 | 
 | 
|---|
| 548 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_body_file (quickmail mailobj, const char* mimetype, const char* path)
 | 
|---|
| 549 | {
 | 
|---|
| 550 |   email_info_attachment_list_add(&mailobj->bodylist, (mimetype ? mimetype : default_mime_type), (mimetype ? mimetype : default_mime_type), (void*)strdup(path), email_info_attachment_open_file, email_info_attachment_read_file, email_info_attachment_close_file, NULL);
 | 
|---|
| 551 | }
 | 
|---|
| 552 | 
 | 
|---|
| 553 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_body_memory (quickmail mailobj, const char* mimetype, char* data, size_t datalen, int mustfree)
 | 
|---|
| 554 | {
 | 
|---|
| 555 |   email_info_attachment_list_add_memory(&mailobj->bodylist, (mimetype ? mimetype : default_mime_type), (mimetype ? mimetype : default_mime_type), data, datalen, mustfree);
 | 
|---|
| 556 | }
 | 
|---|
| 557 | 
 | 
|---|
| 558 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_body_custom (quickmail mailobj, const char* mimetype, char* data, quickmail_attachment_open_fn attachment_data_open, quickmail_attachment_read_fn attachment_data_read, quickmail_attachment_close_fn attachment_data_close, quickmail_attachment_free_filedata_fn attachment_data_filedata_free)
 | 
|---|
| 559 | {
 | 
|---|
| 560 |   email_info_attachment_list_add(&mailobj->bodylist, (mimetype ? mimetype : default_mime_type), (mimetype ? mimetype : default_mime_type), data, (attachment_data_open ? attachment_data_open : email_info_attachment_open_dummy), (attachment_data_read ? attachment_data_read : email_info_attachment_read_dummy), attachment_data_close, attachment_data_filedata_free);
 | 
|---|
| 561 | }
 | 
|---|
| 562 | 
 | 
|---|
| 563 | DLL_EXPORT_LIBQUICKMAIL int quickmail_remove_body (quickmail mailobj, const char* mimetype)
 | 
|---|
| 564 | {
 | 
|---|
| 565 |   return email_info_attachment_list_delete(&mailobj->bodylist, mimetype);
 | 
|---|
| 566 | }
 | 
|---|
| 567 | 
 | 
|---|
| 568 | DLL_EXPORT_LIBQUICKMAIL void quickmail_list_bodies (quickmail mailobj, quickmail_list_attachment_callback_fn callback, void* callbackdata)
 | 
|---|
| 569 | {
 | 
|---|
| 570 |   struct email_info_attachment_list_struct* p = mailobj->bodylist;
 | 
|---|
| 571 |   while (p) {
 | 
|---|
| 572 |     callback(mailobj, p->filename, p->mimetype, p->email_info_attachment_open, p->email_info_attachment_read, p->email_info_attachment_close, callbackdata);
 | 
|---|
| 573 |     p = p->next;
 | 
|---|
| 574 |   }
 | 
|---|
| 575 | }
 | 
|---|
| 576 | 
 | 
|---|
| 577 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_attachment_file (quickmail mailobj, const char* path, const char* mimetype)
 | 
|---|
| 578 | {
 | 
|---|
| 579 |   email_info_attachment_list_add_file(&mailobj->attachmentlist, path, mimetype);
 | 
|---|
| 580 | }
 | 
|---|
| 581 | 
 | 
|---|
| 582 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_attachment_memory (quickmail mailobj, const char* filename, const char* mimetype, char* data, size_t datalen, int mustfree)
 | 
|---|
| 583 | {
 | 
|---|
| 584 |   email_info_attachment_list_add_memory(&mailobj->attachmentlist, filename, mimetype, data, datalen, mustfree);
 | 
|---|
| 585 | }
 | 
|---|
| 586 | 
 | 
|---|
| 587 | DLL_EXPORT_LIBQUICKMAIL void quickmail_add_attachment_custom (quickmail mailobj, const char* filename, const char* mimetype, char* data, quickmail_attachment_open_fn attachment_data_open, quickmail_attachment_read_fn attachment_data_read, quickmail_attachment_close_fn attachment_data_close, quickmail_attachment_free_filedata_fn attachment_data_filedata_free)
 | 
|---|
| 588 | {
 | 
|---|
| 589 |   email_info_attachment_list_add(&mailobj->attachmentlist, filename, mimetype, data, (attachment_data_open ? attachment_data_open : email_info_attachment_open_dummy), (attachment_data_read ? attachment_data_read : email_info_attachment_read_dummy), attachment_data_close, attachment_data_filedata_free);
 | 
|---|
| 590 | }
 | 
|---|
| 591 | 
 | 
|---|
| 592 | DLL_EXPORT_LIBQUICKMAIL int quickmail_remove_attachment (quickmail mailobj, const char* filename)
 | 
|---|
| 593 | {
 | 
|---|
| 594 |   return email_info_attachment_list_delete(&mailobj->attachmentlist, filename);
 | 
|---|
| 595 | }
 | 
|---|
| 596 | 
 | 
|---|
| 597 | DLL_EXPORT_LIBQUICKMAIL void quickmail_list_attachments (quickmail mailobj, quickmail_list_attachment_callback_fn callback, void* callbackdata)
 | 
|---|
| 598 | {
 | 
|---|
| 599 |   struct email_info_attachment_list_struct* p = mailobj->attachmentlist;
 | 
|---|
| 600 |   while (p) {
 | 
|---|
| 601 |     callback(mailobj, p->filename, p->mimetype, p->email_info_attachment_open, p->email_info_attachment_read, p->email_info_attachment_close, callbackdata);
 | 
|---|
| 602 |     p = p->next;
 | 
|---|
| 603 |   }
 | 
|---|
| 604 | }
 | 
|---|
| 605 | 
 | 
|---|
| 606 | DLL_EXPORT_LIBQUICKMAIL void quickmail_set_debug_log (quickmail mailobj, FILE* filehandle)
 | 
|---|
| 607 | {
 | 
|---|
| 608 |   mailobj->debuglog = filehandle;
 | 
|---|
| 609 | }
 | 
|---|
| 610 | 
 | 
|---|
| 611 | DLL_EXPORT_LIBQUICKMAIL void quickmail_fsave (quickmail mailobj, FILE* filehandle)
 | 
|---|
| 612 | {
 | 
|---|
| 613 |   int i;
 | 
|---|
| 614 |   size_t n;
 | 
|---|
| 615 |   char buf[80];
 | 
|---|
| 616 |   while ((n = quickmail_get_data(buf, sizeof(buf), 1, mailobj)) > 0) {
 | 
|---|
| 617 |     for (i = 0; i < n; i++)
 | 
|---|
| 618 |       fprintf(filehandle, "%c", buf[i]);
 | 
|---|
| 619 |   }
 | 
|---|
| 620 | }
 | 
|---|
| 621 | 
 | 
|---|
| 622 | DLL_EXPORT_LIBQUICKMAIL size_t quickmail_get_data (void* ptr, size_t size, size_t nmemb, void* userp)
 | 
|---|
| 623 | {
 | 
|---|
| 624 |   struct email_info_struct* mailobj = (struct email_info_struct*)userp;
 | 
|---|
| 625 | 
 | 
|---|
| 626 |   //abort if no data is requested
 | 
|---|
| 627 |   if (size * nmemb == 0)
 | 
|---|
| 628 |     return 0;
 | 
|---|
| 629 | 
 | 
|---|
| 630 |   //initialize on first run
 | 
|---|
| 631 |   if (mailobj->current == MAILPART_INITIALIZE) {
 | 
|---|
| 632 |     free(mailobj->buf);
 | 
|---|
| 633 |     mailobj->buf = NULL;
 | 
|---|
| 634 |     mailobj->buflen = 0;
 | 
|---|
| 635 |     free(mailobj->mime_boundary_body);
 | 
|---|
| 636 |     mailobj->mime_boundary_body = NULL;
 | 
|---|
| 637 |     free(mailobj->mime_boundary_part);
 | 
|---|
| 638 |     mailobj->mime_boundary_part = NULL;
 | 
|---|
| 639 |     mailobj->current_attachment = mailobj->bodylist;
 | 
|---|
| 640 |     mailobj->current++;
 | 
|---|
| 641 |   }
 | 
|---|
| 642 | 
 | 
|---|
| 643 |   //process current part of mail if no partial data is pending
 | 
|---|
| 644 |   while (mailobj->buflen == 0) {
 | 
|---|
| 645 |     if (mailobj->buflen == 0 && mailobj->current == MAILPART_HEADER) {
 | 
|---|
| 646 |       char* s;
 | 
|---|
| 647 |       //generate header part
 | 
|---|
| 648 |       char** p = &mailobj->buf;
 | 
|---|
| 649 |       mailobj->buf = NULL;
 | 
|---|
| 650 |       str_append(p, "User-Agent: libquickmail v" LIBQUICKMAIL_VERSION NEWLINE);
 | 
|---|
| 651 |       if (mailobj->timestamp != 0) {
 | 
|---|
| 652 |         char timestamptext[32];
 | 
|---|
| 653 |         if (strftime(timestamptext, sizeof(timestamptext), "%a, %d %b %Y %H:%M:%S %z", localtime(&mailobj->timestamp))) {
 | 
|---|
| 654 |           str_append(p, "Date: ");
 | 
|---|
| 655 |           str_append(p, timestamptext);
 | 
|---|
| 656 |           str_append(p, NEWLINE);
 | 
|---|
| 657 |         }
 | 
|---|
| 658 | #ifdef _WIN32
 | 
|---|
| 659 |         //fallback method for Windows when %z (time zone offset) fails
 | 
|---|
| 660 |         else if (strftime(timestamptext, sizeof(timestamptext), "%a, %d %b %Y %H:%M:%S", localtime(&mailobj->timestamp))) {
 | 
|---|
| 661 |           TIME_ZONE_INFORMATION tzinfo;
 | 
|---|
| 662 |           if (GetTimeZoneInformation(&tzinfo) != TIME_ZONE_ID_INVALID)
 | 
|---|
| 663 |             sprintf(timestamptext + strlen(timestamptext), " %c%02i%02i", (tzinfo.Bias > 0 ? '-' : '+'), (int)-tzinfo.Bias / 60, (int)-tzinfo.Bias % 60);
 | 
|---|
| 664 |           str_append(p, "Date: ");
 | 
|---|
| 665 |           str_append(p, timestamptext);
 | 
|---|
| 666 |           str_append(p, NEWLINE);
 | 
|---|
| 667 |         }
 | 
|---|
| 668 | #endif
 | 
|---|
| 669 |       }
 | 
|---|
| 670 |       if (mailobj->from && *mailobj->from) {
 | 
|---|
| 671 |         str_append(p, "From: <");
 | 
|---|
| 672 |         str_append(p, mailobj->from);
 | 
|---|
| 673 |         str_append(p, ">" NEWLINE);
 | 
|---|
| 674 |       }
 | 
|---|
| 675 |       if ((s = email_info_string_list_concatenate(mailobj->to)) != NULL) {
 | 
|---|
| 676 |         str_append(p, "To: ");
 | 
|---|
| 677 |         str_append(p, s);
 | 
|---|
| 678 |         str_append(p, NEWLINE);
 | 
|---|
| 679 |         free(s);
 | 
|---|
| 680 |       }
 | 
|---|
| 681 |       if ((s = email_info_string_list_concatenate(mailobj->cc)) != NULL) {
 | 
|---|
| 682 |         str_append(p, "Cc: ");
 | 
|---|
| 683 |         str_append(p, s);
 | 
|---|
| 684 |         str_append(p, NEWLINE);
 | 
|---|
| 685 |         free(s);
 | 
|---|
| 686 |       }
 | 
|---|
| 687 |       if (mailobj->subject) {
 | 
|---|
| 688 |         str_append(p, "Subject: ");
 | 
|---|
| 689 |         str_append(p, mailobj->subject);
 | 
|---|
| 690 |         str_append(p, NEWLINE);
 | 
|---|
| 691 |       }
 | 
|---|
| 692 |       if (mailobj->header) {
 | 
|---|
| 693 |         str_append(p, mailobj->header);
 | 
|---|
| 694 |       }
 | 
|---|
| 695 |       if (mailobj->attachmentlist) {
 | 
|---|
| 696 |         str_append(p, "MIME-Version: 1.0" NEWLINE);
 | 
|---|
| 697 |       }
 | 
|---|
| 698 |       if (mailobj->attachmentlist) {
 | 
|---|
| 699 |         mailobj->mime_boundary_part = randomize_zeros(strdup("=PART=SEPARATOR=_0000_0000_0000_0000_0000_0000_="));
 | 
|---|
| 700 |         str_append(p, "Content-Type: multipart/mixed; boundary=\"");
 | 
|---|
| 701 |         str_append(p, mailobj->mime_boundary_part);
 | 
|---|
| 702 |         str_append(p, "\"" NEWLINE NEWLINE "This is a multipart message in MIME format." NEWLINE NEWLINE "--");
 | 
|---|
| 703 |         str_append(p, mailobj->mime_boundary_part);
 | 
|---|
| 704 |         str_append(p, NEWLINE);
 | 
|---|
| 705 |       }
 | 
|---|
| 706 |       if (mailobj->bodylist && mailobj->bodylist->next) {
 | 
|---|
| 707 |         mailobj->mime_boundary_body = randomize_zeros(strdup("=BODY=SEPARATOR=_0000_0000_0000_0000_0000_0000_="));
 | 
|---|
| 708 |         str_append(p, "Content-Type: multipart/alternative; boundary=\"");
 | 
|---|
| 709 |         str_append(p, mailobj->mime_boundary_body);
 | 
|---|
| 710 |         str_append(p, NEWLINE);
 | 
|---|
| 711 |       }
 | 
|---|
| 712 |       mailobj->buflen = strlen(mailobj->buf);
 | 
|---|
| 713 |       mailobj->current++;
 | 
|---|
| 714 |     }
 | 
|---|
| 715 |     if (mailobj->buflen == 0 && mailobj->current == MAILPART_BODY) {
 | 
|---|
| 716 |       if (mailobj->current_attachment) {
 | 
|---|
| 717 |         if (!mailobj->current_attachment->handle) {
 | 
|---|
| 718 |           //open file with body data
 | 
|---|
| 719 |           while (mailobj->current_attachment) {
 | 
|---|
| 720 |             if ((mailobj->current_attachment->handle = mailobj->current_attachment->email_info_attachment_open(mailobj->current_attachment->filedata)) != NULL) {
 | 
|---|
| 721 |               break;
 | 
|---|
| 722 |             }
 | 
|---|
| 723 |             mailobj->current_attachment = mailobj->current_attachment->next;
 | 
|---|
| 724 |           }
 | 
|---|
| 725 |           if (!mailobj->current_attachment) {
 | 
|---|
| 726 |             mailobj->current_attachment = mailobj->attachmentlist;
 | 
|---|
| 727 |             mailobj->current++;
 | 
|---|
| 728 |           }
 | 
|---|
| 729 |           //generate attachment header
 | 
|---|
| 730 |           if (mailobj->current_attachment && mailobj->current_attachment->handle) {
 | 
|---|
| 731 |             mailobj->buf = NULL;
 | 
|---|
| 732 |             if (mailobj->mime_boundary_body) {
 | 
|---|
| 733 |               mailobj->buf = str_append(&mailobj->buf, NEWLINE "--");
 | 
|---|
| 734 |               mailobj->buf = str_append(&mailobj->buf, mailobj->mime_boundary_body);
 | 
|---|
| 735 |               mailobj->buf = str_append(&mailobj->buf, NEWLINE);
 | 
|---|
| 736 |             }
 | 
|---|
| 737 |             mailobj->buf = str_append(&mailobj->buf, "Content-Type: ");
 | 
|---|
| 738 |             mailobj->buf = str_append(&mailobj->buf, (mailobj->bodylist && mailobj->current_attachment->filename ? mailobj->current_attachment->filename : default_mime_type));
 | 
|---|
| 739 |             mailobj->buf = str_append(&mailobj->buf, NEWLINE "Content-Transfer-Encoding: 8bit" NEWLINE "Content-Disposition: inline" NEWLINE NEWLINE);
 | 
|---|
| 740 |             mailobj->buflen = strlen(mailobj->buf);
 | 
|---|
| 741 |           }
 | 
|---|
| 742 |         }
 | 
|---|
| 743 |         if (mailobj->buflen == 0 && mailobj->current_attachment && mailobj->current_attachment->handle) {
 | 
|---|
| 744 |           //read body data
 | 
|---|
| 745 |           if ((mailobj->buf = malloc(BODY_BUFFER_SIZE)) == NULL) {
 | 
|---|
| 746 |             DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 747 |           }
 | 
|---|
| 748 |           if (mailobj->buf == NULL || (mailobj->buflen = mailobj->current_attachment->email_info_attachment_read(mailobj->current_attachment->handle, mailobj->buf, BODY_BUFFER_SIZE)) <= 0) {
 | 
|---|
| 749 |             //end of file
 | 
|---|
| 750 |             free(mailobj->buf);
 | 
|---|
| 751 |             mailobj->buflen = 0;
 | 
|---|
| 752 |             if (mailobj->current_attachment->email_info_attachment_close)
 | 
|---|
| 753 |               mailobj->current_attachment->email_info_attachment_close(mailobj->current_attachment->handle);
 | 
|---|
| 754 |             //else
 | 
|---|
| 755 |             //  free(mailobj->current_attachment->handle);
 | 
|---|
| 756 |             mailobj->current_attachment->handle = NULL;
 | 
|---|
| 757 |             mailobj->current_attachment = mailobj->current_attachment->next;
 | 
|---|
| 758 |           }
 | 
|---|
| 759 |         }
 | 
|---|
| 760 |       } else {
 | 
|---|
| 761 |         mailobj->current_attachment = mailobj->attachmentlist;
 | 
|---|
| 762 |         mailobj->current++;
 | 
|---|
| 763 |       }
 | 
|---|
| 764 |     }
 | 
|---|
| 765 |     if (mailobj->buflen == 0 && mailobj->current == MAILPART_BODY_DONE) {
 | 
|---|
| 766 |       mailobj->buf = NULL;
 | 
|---|
| 767 |       if (mailobj->mime_boundary_body) {
 | 
|---|
| 768 |         mailobj->buf = str_append(&mailobj->buf, NEWLINE "--");
 | 
|---|
| 769 |         mailobj->buf = str_append(&mailobj->buf, mailobj->mime_boundary_body);
 | 
|---|
| 770 |         mailobj->buf = str_append(&mailobj->buf, "--" NEWLINE);
 | 
|---|
| 771 |         mailobj->buflen = strlen(mailobj->buf);
 | 
|---|
| 772 |         free(mailobj->mime_boundary_body);
 | 
|---|
| 773 |         mailobj->mime_boundary_body = NULL;
 | 
|---|
| 774 |       }
 | 
|---|
| 775 |       mailobj->current++;
 | 
|---|
| 776 |     }
 | 
|---|
| 777 |     if (mailobj->buflen == 0 && mailobj->current == MAILPART_ATTACHMENT) {
 | 
|---|
| 778 |       if (mailobj->current_attachment) {
 | 
|---|
| 779 |         if (!mailobj->current_attachment->handle) {
 | 
|---|
| 780 |           //open file to attach
 | 
|---|
| 781 |           while (mailobj->current_attachment) {
 | 
|---|
| 782 |             if ((mailobj->current_attachment->handle = mailobj->current_attachment->email_info_attachment_open(mailobj->current_attachment->filedata)) != NULL) {
 | 
|---|
| 783 |               break;
 | 
|---|
| 784 |             }
 | 
|---|
| 785 |             mailobj->current_attachment = mailobj->current_attachment->next;
 | 
|---|
| 786 |           }
 | 
|---|
| 787 |           //generate attachment header
 | 
|---|
| 788 |           if (mailobj->current_attachment && mailobj->current_attachment->handle) {
 | 
|---|
| 789 |             mailobj->buf = NULL;
 | 
|---|
| 790 |             if (mailobj->mime_boundary_part) {
 | 
|---|
| 791 |               mailobj->buf = str_append(&mailobj->buf, NEWLINE "--");
 | 
|---|
| 792 |               mailobj->buf = str_append(&mailobj->buf, mailobj->mime_boundary_part);
 | 
|---|
| 793 |               mailobj->buf = str_append(&mailobj->buf, NEWLINE);
 | 
|---|
| 794 |             }
 | 
|---|
| 795 |             mailobj->buf = str_append(&mailobj->buf, "Content-Type: ");
 | 
|---|
| 796 |             mailobj->buf = str_append(&mailobj->buf, (mailobj->current_attachment->mimetype ? mailobj->current_attachment->mimetype : "application/octet-stream"));
 | 
|---|
| 797 |             mailobj->buf = str_append(&mailobj->buf, "; Name=\"");
 | 
|---|
| 798 |             mailobj->buf = str_append(&mailobj->buf, mailobj->current_attachment->filename);
 | 
|---|
| 799 |             mailobj->buf = str_append(&mailobj->buf, "\"" NEWLINE "Content-Transfer-Encoding: base64" NEWLINE NEWLINE);
 | 
|---|
| 800 |             mailobj->buflen = strlen(mailobj->buf);
 | 
|---|
| 801 |           }
 | 
|---|
| 802 |         } else {
 | 
|---|
| 803 |           //generate next line of attachment data
 | 
|---|
| 804 |           size_t n = 0;
 | 
|---|
| 805 |           int mimelinepos = 0;
 | 
|---|
| 806 |           unsigned char igroup[3] = {0, 0, 0};
 | 
|---|
| 807 |           unsigned char ogroup[4];
 | 
|---|
| 808 |           mailobj->buflen = 0;
 | 
|---|
| 809 |           if ((mailobj->buf = (char*)malloc(MIME_LINE_WIDTH + NEWLINELENGTH + 1)) == NULL) {
 | 
|---|
| 810 |             DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 811 |             n = 0;
 | 
|---|
| 812 |           } else {
 | 
|---|
| 813 |             while (mimelinepos < MIME_LINE_WIDTH && (n = mailobj->current_attachment->email_info_attachment_read(mailobj->current_attachment->handle, igroup, 3)) > 0) {
 | 
|---|
| 814 |               //code data
 | 
|---|
| 815 |               ogroup[0] = mailobj->dtable[igroup[0] >> 2];
 | 
|---|
| 816 |               ogroup[1] = mailobj->dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
 | 
|---|
| 817 |               ogroup[2] = mailobj->dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
 | 
|---|
| 818 |               ogroup[3] = mailobj->dtable[igroup[2] & 0x3F];
 | 
|---|
| 819 |               //padd with "=" characters if less than 3 characters were read
 | 
|---|
| 820 |               if (n < 3) {
 | 
|---|
| 821 |                 ogroup[3] = '=';
 | 
|---|
| 822 |                 if (n < 2)
 | 
|---|
| 823 |                   ogroup[2] = '=';
 | 
|---|
| 824 |               }
 | 
|---|
| 825 |               memcpy(mailobj->buf + mimelinepos, ogroup, 4);
 | 
|---|
| 826 |               mailobj->buflen += 4;
 | 
|---|
| 827 |               mimelinepos += 4;
 | 
|---|
| 828 |             }
 | 
|---|
| 829 |             if (mimelinepos > 0) {
 | 
|---|
| 830 |               memcpy(mailobj->buf + mimelinepos, NEWLINE, NEWLINELENGTH);
 | 
|---|
| 831 |               mailobj->buflen += NEWLINELENGTH;
 | 
|---|
| 832 |             }
 | 
|---|
| 833 |           }
 | 
|---|
| 834 |           if (n <= 0) {
 | 
|---|
| 835 |             //end of file
 | 
|---|
| 836 |             if (mailobj->current_attachment->email_info_attachment_close)
 | 
|---|
| 837 |               mailobj->current_attachment->email_info_attachment_close(mailobj->current_attachment->handle);
 | 
|---|
| 838 |             else
 | 
|---|
| 839 |               free(mailobj->current_attachment->handle);
 | 
|---|
| 840 |             mailobj->current_attachment->handle = NULL;
 | 
|---|
| 841 |             mailobj->current_attachment = mailobj->current_attachment->next;
 | 
|---|
| 842 |           }
 | 
|---|
| 843 |         }
 | 
|---|
| 844 |       } else {
 | 
|---|
| 845 |         mailobj->current++;
 | 
|---|
| 846 |       }
 | 
|---|
| 847 |     }
 | 
|---|
| 848 |     if (mailobj->buflen == 0 && mailobj->current == MAILPART_END) {
 | 
|---|
| 849 |       mailobj->buf = NULL;
 | 
|---|
| 850 |       mailobj->buflen = 0;
 | 
|---|
| 851 |       if (mailobj->mime_boundary_part) {
 | 
|---|
| 852 |         mailobj->buf = str_append(&mailobj->buf, NEWLINE "--");
 | 
|---|
| 853 |         mailobj->buf = str_append(&mailobj->buf, mailobj->mime_boundary_part);
 | 
|---|
| 854 |         mailobj->buf = str_append(&mailobj->buf, "--" NEWLINE);
 | 
|---|
| 855 |         mailobj->buflen = strlen(mailobj->buf);
 | 
|---|
| 856 |         free(mailobj->mime_boundary_part);
 | 
|---|
| 857 |         mailobj->mime_boundary_part = NULL;
 | 
|---|
| 858 |       }
 | 
|---|
| 859 |       //mailobj->buf = str_append(&mailobj->buf, NEWLINE "." NEWLINE);
 | 
|---|
| 860 |       //mailobj->buflen = strlen(mailobj->buf);
 | 
|---|
| 861 |       mailobj->current++;
 | 
|---|
| 862 |     }
 | 
|---|
| 863 |     if (mailobj->buflen == 0 && mailobj->current == MAILPART_DONE) {
 | 
|---|
| 864 |       break;
 | 
|---|
| 865 |     }
 | 
|---|
| 866 |   }
 | 
|---|
| 867 | 
 | 
|---|
| 868 |   //flush pending data if any
 | 
|---|
| 869 |   if (mailobj->buflen > 0) {
 | 
|---|
| 870 |     int len = (mailobj->buflen > size * nmemb ? size * nmemb : mailobj->buflen);
 | 
|---|
| 871 |     memcpy(ptr, mailobj->buf, len);
 | 
|---|
| 872 |     if (len < mailobj->buflen) {
 | 
|---|
| 873 |       mailobj->buf = memmove(mailobj->buf, mailobj->buf + len, mailobj->buflen - len);
 | 
|---|
| 874 |       mailobj->buflen -= len;
 | 
|---|
| 875 |     } else {
 | 
|---|
| 876 |       free(mailobj->buf);
 | 
|---|
| 877 |       mailobj->buf = NULL;
 | 
|---|
| 878 |       mailobj->buflen = 0;
 | 
|---|
| 879 |     }
 | 
|---|
| 880 |     return len;
 | 
|---|
| 881 |   }
 | 
|---|
| 882 | 
 | 
|---|
| 883 |   //if (mailobj->current != MAILPART_DONE)
 | 
|---|
| 884 |   //  ;//this should never be reached
 | 
|---|
| 885 |   mailobj->current = 0;
 | 
|---|
| 886 |   return 0;
 | 
|---|
| 887 | }
 | 
|---|
| 888 | 
 | 
|---|
| 889 | #ifndef NOCURL
 | 
|---|
| 890 | char* add_angle_brackets (const char* data)
 | 
|---|
| 891 | {
 | 
|---|
| 892 |   size_t datalen = strlen(data);
 | 
|---|
| 893 |   char* result;
 | 
|---|
| 894 |   if ((result = (char*)malloc(datalen + 3)) == NULL) {
 | 
|---|
| 895 |     DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 896 |     return NULL;
 | 
|---|
| 897 |   }
 | 
|---|
| 898 |   result[0] = '<';
 | 
|---|
| 899 |   memcpy(result + 1, data, datalen);
 | 
|---|
| 900 |   result[datalen + 1] = '>';
 | 
|---|
| 901 |   result[datalen + 2] = 0;
 | 
|---|
| 902 |   return result;
 | 
|---|
| 903 | }
 | 
|---|
| 904 | #endif
 | 
|---|
| 905 | 
 | 
|---|
| 906 | DLL_EXPORT_LIBQUICKMAIL const char* quickmail_send (quickmail mailobj, const char* smtpserver, unsigned int smtpport, const char* username, const char* password)
 | 
|---|
| 907 | {
 | 
|---|
| 908 | #ifndef NOCURL
 | 
|---|
| 909 |   //libcurl based sending
 | 
|---|
| 910 |   CURL *curl;
 | 
|---|
| 911 |   CURLcode result = CURLE_FAILED_INIT;
 | 
|---|
| 912 |   //curl_global_init(CURL_GLOBAL_ALL);
 | 
|---|
| 913 |   if ((curl = curl_easy_init()) != NULL) {
 | 
|---|
| 914 |     struct curl_slist *recipients = NULL;
 | 
|---|
| 915 |     struct email_info_email_list_struct* listentry;
 | 
|---|
| 916 |     //set destination URL
 | 
|---|
| 917 |     char* addr;
 | 
|---|
| 918 |     size_t len = strlen(smtpserver) + 14;
 | 
|---|
| 919 |     if ((addr = (char*)malloc(len)) == NULL) {
 | 
|---|
| 920 |       DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 921 |       return ERRMSG_MEMORY_ALLOCATION_ERROR;
 | 
|---|
| 922 |     }
 | 
|---|
| 923 |     snprintf(addr, len, "smtp://%s:%u", smtpserver, smtpport);
 | 
|---|
| 924 |     curl_easy_setopt(curl, CURLOPT_URL, addr);
 | 
|---|
| 925 |     free(addr);
 | 
|---|
| 926 |     //try Transport Layer Security (TLS), but continue anyway if it fails
 | 
|---|
| 927 |     curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
 | 
|---|
| 928 |     //don't fail if the TLS/SSL a certificate could not be verified
 | 
|---|
| 929 |     //alternative: add the issuer certificate (or the host certificate if
 | 
|---|
| 930 |     //the certificate is self-signed) to the set of certificates that are
 | 
|---|
| 931 |     //known to libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH
 | 
|---|
| 932 |     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
 | 
|---|
| 933 |     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
 | 
|---|
| 934 |     //set authentication credentials if provided
 | 
|---|
| 935 |     if (username && *username)
 | 
|---|
| 936 |       curl_easy_setopt(curl, CURLOPT_USERNAME, username);
 | 
|---|
| 937 |     if (password)
 | 
|---|
| 938 |       curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
 | 
|---|
| 939 |     //set from value for envelope reverse-path
 | 
|---|
| 940 |     if (mailobj->from && *mailobj->from) {
 | 
|---|
| 941 |       addr = add_angle_brackets(mailobj->from);
 | 
|---|
| 942 |       curl_easy_setopt(curl, CURLOPT_MAIL_FROM, addr);
 | 
|---|
| 943 |       free(addr);
 | 
|---|
| 944 |     }
 | 
|---|
| 945 |     //set recipients
 | 
|---|
| 946 |     listentry = mailobj->to;
 | 
|---|
| 947 |     while (listentry) {
 | 
|---|
| 948 |       if (listentry->data && *listentry->data) {
 | 
|---|
| 949 |         addr = add_angle_brackets(listentry->data);
 | 
|---|
| 950 |         recipients = curl_slist_append(recipients, addr);
 | 
|---|
| 951 |         free(addr);
 | 
|---|
| 952 |       }
 | 
|---|
| 953 |       listentry = listentry->next;
 | 
|---|
| 954 |     }
 | 
|---|
| 955 |     listentry = mailobj->cc;
 | 
|---|
| 956 |     while (listentry) {
 | 
|---|
| 957 |       if (listentry->data && *listentry->data) {
 | 
|---|
| 958 |         addr = add_angle_brackets(listentry->data);
 | 
|---|
| 959 |         recipients = curl_slist_append(recipients, addr);
 | 
|---|
| 960 |         free(addr);
 | 
|---|
| 961 |       }
 | 
|---|
| 962 |       listentry = listentry->next;
 | 
|---|
| 963 |     }
 | 
|---|
| 964 |     listentry = mailobj->bcc;
 | 
|---|
| 965 |     while (listentry) {
 | 
|---|
| 966 |       if (listentry->data && *listentry->data) {
 | 
|---|
| 967 |         addr = add_angle_brackets(listentry->data);
 | 
|---|
| 968 |         recipients = curl_slist_append(recipients, addr);
 | 
|---|
| 969 |         free(addr);
 | 
|---|
| 970 |       }
 | 
|---|
| 971 |       listentry = listentry->next;
 | 
|---|
| 972 |     }
 | 
|---|
| 973 |     curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
 | 
|---|
| 974 |     //set callback function for getting message body
 | 
|---|
| 975 |     curl_easy_setopt(curl, CURLOPT_READFUNCTION, quickmail_get_data);
 | 
|---|
| 976 |     curl_easy_setopt(curl, CURLOPT_READDATA, mailobj);
 | 
|---|
| 977 |     //enable debugging if requested
 | 
|---|
| 978 |     if (mailobj->debuglog) {
 | 
|---|
| 979 |       curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
 | 
|---|
| 980 |       curl_easy_setopt(curl, CURLOPT_STDERR, mailobj->debuglog);
 | 
|---|
| 981 |     }
 | 
|---|
| 982 |     //send the message
 | 
|---|
| 983 |     result = curl_easy_perform(curl);
 | 
|---|
| 984 |     //free the list of recipients and clean up
 | 
|---|
| 985 |     curl_slist_free_all(recipients);
 | 
|---|
| 986 |     curl_easy_cleanup(curl);
 | 
|---|
| 987 |   }
 | 
|---|
| 988 |   return (result == CURLE_OK ? NULL : curl_easy_strerror(result));
 | 
|---|
| 989 | #else
 | 
|---|
| 990 |   //minimal implementation without libcurl
 | 
|---|
| 991 |   SOCKET sock;
 | 
|---|
| 992 |   char* errmsg = NULL;
 | 
|---|
| 993 |   struct email_info_email_list_struct* listentry;
 | 
|---|
| 994 |   char local_hostname[64];
 | 
|---|
| 995 |   int statuscode;
 | 
|---|
| 996 |   //determine local host name
 | 
|---|
| 997 |   if (gethostname(local_hostname, sizeof(local_hostname)) != 0)
 | 
|---|
| 998 |                 strcpy(local_hostname, "localhost");
 | 
|---|
| 999 |   //connect
 | 
|---|
| 1000 |   if ((sock = socket_open(smtpserver, smtpport, &errmsg)) != INVALID_SOCKET) {
 | 
|---|
| 1001 |     //talk with SMTP server
 | 
|---|
| 1002 |     if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, NULL)) >= 400) {
 | 
|---|
| 1003 |       errmsg = "SMTP server returned an error on connection";
 | 
|---|
| 1004 |     } else {
 | 
|---|
| 1005 |       size_t n;
 | 
|---|
| 1006 |       char buf[WRITE_BUFFER_CHUNK_SIZE];
 | 
|---|
| 1007 |       do {
 | 
|---|
| 1008 |         if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "EHLO %s", local_hostname)) >= 400) {
 | 
|---|
| 1009 |           if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "HELO %s", local_hostname)) >= 400) {
 | 
|---|
| 1010 |             errmsg = "SMTP EHLO/HELO returned error";
 | 
|---|
| 1011 |             break;
 | 
|---|
| 1012 |           }
 | 
|---|
| 1013 |         }
 | 
|---|
| 1014 |         //authenticate if needed
 | 
|---|
| 1015 |         if (username || password) {
 | 
|---|
| 1016 |           int len;
 | 
|---|
| 1017 |           int inpos = 0;
 | 
|---|
| 1018 |           int outpos = 0;
 | 
|---|
| 1019 |           size_t usernamelen = (username ? strlen(username) : 0);
 | 
|---|
| 1020 |           size_t passwordlen = (password ? strlen(password) : 0);
 | 
|---|
| 1021 |           char* auth;
 | 
|---|
| 1022 |           char* base64auth;
 | 
|---|
| 1023 |           if ((auth = (char*)malloc(usernamelen + passwordlen + 4)) == NULL) {
 | 
|---|
| 1024 |             DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 1025 |             return ERRMSG_MEMORY_ALLOCATION_ERROR;
 | 
|---|
| 1026 |           }
 | 
|---|
| 1027 |           if ((base64auth = (char*)malloc(((usernamelen + passwordlen + 2) + 2) / 3 * 4 + 1)) == NULL) {
 | 
|---|
| 1028 |             DEBUG_ERROR(ERRMSG_MEMORY_ALLOCATION_ERROR)
 | 
|---|
| 1029 |             return ERRMSG_MEMORY_ALLOCATION_ERROR;
 | 
|---|
| 1030 |           }
 | 
|---|
| 1031 |           //leave the authorization identity empty to indicate it's the same the as authentication identity
 | 
|---|
| 1032 |           auth[0] = 0;
 | 
|---|
| 1033 |           len = 1;
 | 
|---|
| 1034 |           //set the authentication identity
 | 
|---|
| 1035 |           memcpy(auth + len, (username ? username : ""), usernamelen + 1);
 | 
|---|
| 1036 |           len += usernamelen + 1;
 | 
|---|
| 1037 |           //set the password
 | 
|---|
| 1038 |           memcpy(auth + len, (password ? password : ""), passwordlen + 1);
 | 
|---|
| 1039 |           len += passwordlen;
 | 
|---|
| 1040 |           //padd with extra zero so groups of 3 bytes can be read
 | 
|---|
| 1041 |           auth[usernamelen + len + 1] = 0;
 | 
|---|
| 1042 |           //encode in base64
 | 
|---|
| 1043 |           while (inpos < len) {
 | 
|---|
| 1044 |             //encode data
 | 
|---|
| 1045 |             base64auth[outpos + 0] = mailobj->dtable[auth[inpos + 0] >> 2];
 | 
|---|
| 1046 |             base64auth[outpos + 1] = mailobj->dtable[((auth[inpos + 0] & 3) << 4) | (auth[inpos + 1] >> 4)];
 | 
|---|
| 1047 |             base64auth[outpos + 2] = mailobj->dtable[((auth[inpos + 1] & 0xF) << 2) | (auth[inpos + 2] >> 6)];
 | 
|---|
| 1048 |             base64auth[outpos + 3] = mailobj->dtable[auth[inpos + 2] & 0x3F];
 | 
|---|
| 1049 |             //padd with "=" characters if less than 3 characters were read
 | 
|---|
| 1050 |             if (inpos + 1 >= len) {
 | 
|---|
| 1051 |               base64auth[outpos + 3] = '=';
 | 
|---|
| 1052 |               if (inpos + 2 >= len)
 | 
|---|
| 1053 |                 base64auth[outpos + 2] = '=';
 | 
|---|
| 1054 |             }
 | 
|---|
| 1055 |             //advance to next position
 | 
|---|
| 1056 |             inpos += 3;
 | 
|---|
| 1057 |             outpos += 4;
 | 
|---|
| 1058 |           }
 | 
|---|
| 1059 |           base64auth[outpos] = 0;
 | 
|---|
| 1060 |           //send originator e-mail address
 | 
|---|
| 1061 |           if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "AUTH PLAIN %s", base64auth)) >= 400) {
 | 
|---|
| 1062 |             errmsg = "SMTP authentication failed";
 | 
|---|
| 1063 |             break;
 | 
|---|
| 1064 |           }
 | 
|---|
| 1065 |         }
 | 
|---|
| 1066 |         //send originator e-mail address
 | 
|---|
| 1067 |         if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "MAIL FROM:<%s>", mailobj->from)) >= 400) {
 | 
|---|
| 1068 |           errmsg = "SMTP server did not accept sender";
 | 
|---|
| 1069 |           break;
 | 
|---|
| 1070 |         }
 | 
|---|
| 1071 |         //send recipient e-mail addresses
 | 
|---|
| 1072 |         listentry = mailobj->to;
 | 
|---|
| 1073 |         while (!errmsg && listentry) {
 | 
|---|
| 1074 |           if (listentry->data && *listentry->data) {
 | 
|---|
| 1075 |             if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "RCPT TO:<%s>", listentry->data)) >= 400)
 | 
|---|
| 1076 |               errmsg = "SMTP server did not accept e-mail address (To)";
 | 
|---|
| 1077 |           }
 | 
|---|
| 1078 |           listentry = listentry->next;
 | 
|---|
| 1079 |         }
 | 
|---|
| 1080 |         listentry = mailobj->cc;
 | 
|---|
| 1081 |         while (!errmsg && listentry) {
 | 
|---|
| 1082 |           if (listentry->data && *listentry->data) {
 | 
|---|
| 1083 |             if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "RCPT TO:<%s>", listentry->data)) >= 400)
 | 
|---|
| 1084 |               errmsg = "SMTP server did not accept e-mail address (CC)";
 | 
|---|
| 1085 |           }
 | 
|---|
| 1086 |           listentry = listentry->next;
 | 
|---|
| 1087 |         }
 | 
|---|
| 1088 |         listentry = mailobj->bcc;
 | 
|---|
| 1089 |         while (!errmsg && listentry) {
 | 
|---|
| 1090 |           if (listentry->data && *listentry->data) {
 | 
|---|
| 1091 |             if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "RCPT TO:<%s>", listentry->data)) >= 400)
 | 
|---|
| 1092 |               errmsg = "SMTP server did not accept e-mail address (BCC)";
 | 
|---|
| 1093 |           }
 | 
|---|
| 1094 |           listentry = listentry->next;
 | 
|---|
| 1095 |         }
 | 
|---|
| 1096 |         if (errmsg)
 | 
|---|
| 1097 |           break;
 | 
|---|
| 1098 |         //prepare to send mail body
 | 
|---|
| 1099 |         if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "DATA")) >= 400) {
 | 
|---|
| 1100 |           errmsg = "SMTP DATA returned error";
 | 
|---|
| 1101 |           break;
 | 
|---|
| 1102 |         }
 | 
|---|
| 1103 |         //send mail body data
 | 
|---|
| 1104 |         while ((n = quickmail_get_data(buf, sizeof(buf), 1, mailobj)) > 0) {
 | 
|---|
| 1105 |           socket_send(sock, buf, n);
 | 
|---|
| 1106 |         }
 | 
|---|
| 1107 |         //send end of data
 | 
|---|
| 1108 |         if ((statuscode = socket_smtp_command(sock, mailobj->debuglog, "\r\n.")) >= 400) {
 | 
|---|
| 1109 |           errmsg = "SMTP error after sending message data";
 | 
|---|
| 1110 |           break;
 | 
|---|
| 1111 |         }
 | 
|---|
| 1112 |       } while (0);
 | 
|---|
| 1113 |       //log out
 | 
|---|
| 1114 |       socket_smtp_command(sock, mailobj->debuglog, "QUIT");
 | 
|---|
| 1115 |     }
 | 
|---|
| 1116 |   }
 | 
|---|
| 1117 |   //close socket
 | 
|---|
| 1118 |   socket_close(sock);
 | 
|---|
| 1119 |   return errmsg;
 | 
|---|
| 1120 | #endif
 | 
|---|
| 1121 | }
 | 
|---|