summaryrefslogtreecommitdiff
path: root/noncore/net/mail/smtpwrapper.cpp
Unidiff
Diffstat (limited to 'noncore/net/mail/smtpwrapper.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/net/mail/smtpwrapper.cpp604
1 files changed, 604 insertions, 0 deletions
diff --git a/noncore/net/mail/smtpwrapper.cpp b/noncore/net/mail/smtpwrapper.cpp
new file mode 100644
index 0000000..162b1b9
--- a/dev/null
+++ b/noncore/net/mail/smtpwrapper.cpp
@@ -0,0 +1,604 @@
1#include <stdlib.h>
2#include <sys/stat.h>
3#include <sys/types.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <string.h>
7#include <qdir.h>
8
9#include <libetpan/mailmime.h>
10#include <libetpan/mailimf.h>
11#include <libetpan/mailsmtp.h>
12#include <libetpan/mailstorage.h>
13#include <libetpan/maildriver.h>
14
15#include "smtpwrapper.h"
16#include "mailwrapper.h"
17#include "logindialog.h"
18#include "defines.h"
19
20SMTPwrapper::SMTPwrapper( Settings *s )
21 : QObject()
22{
23 settings = s;
24}
25
26QString SMTPwrapper::mailsmtpError( int errnum )
27{
28 switch ( errnum ) {
29 case MAILSMTP_NO_ERROR:
30 return tr( "No error" );
31 case MAILSMTP_ERROR_UNEXPECTED_CODE:
32 return tr( "Unexpected error code" );
33 case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE:
34 return tr( "Service not available" );
35 case MAILSMTP_ERROR_STREAM:
36 return tr( "Stream error" );
37 case MAILSMTP_ERROR_HOSTNAME:
38 return tr( "gethostname() failed" );
39 case MAILSMTP_ERROR_NOT_IMPLEMENTED:
40 return tr( "Not implemented" );
41 case MAILSMTP_ERROR_ACTION_NOT_TAKEN:
42 return tr( "Error, action not taken" );
43 case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION:
44 return tr( "Data exceeds storage allocation" );
45 case MAILSMTP_ERROR_IN_PROCESSING:
46 return tr( "Error in processing" );
47 // case MAILSMTP_ERROR_INSUFFISANT_SYSTEM_STORAGE:
48 // return tr( "Insufficient system storage" );
49 case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE:
50 return tr( "Mailbox unavailable" );
51 case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED:
52 return tr( "Mailbox name not allowed" );
53 case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND:
54 return tr( "Bad command sequence" );
55 case MAILSMTP_ERROR_USER_NOT_LOCAL:
56 return tr( "User not local" );
57 case MAILSMTP_ERROR_TRANSACTION_FAILED:
58 return tr( "Transaction failed" );
59 case MAILSMTP_ERROR_MEMORY:
60 return tr( "Memory error" );
61 case MAILSMTP_ERROR_CONNECTION_REFUSED:
62 return tr( "Connection refused" );
63 default:
64 return tr( "Unknown error code" );
65 }
66}
67
68mailimf_mailbox *SMTPwrapper::newMailbox(const QString&name, const QString&mail )
69{
70 return mailimf_mailbox_new( strdup( name.latin1() ),
71 strdup( mail.latin1() ) );
72}
73
74mailimf_address_list *SMTPwrapper::parseAddresses(const QString&addr )
75{
76 mailimf_address_list *addresses;
77
78 if ( addr.isEmpty() ) return NULL;
79
80 addresses = mailimf_address_list_new_empty();
81
82 QStringList list = QStringList::split( ',', addr );
83 QStringList::Iterator it;
84 for ( it = list.begin(); it != list.end(); it++ ) {
85 char *str = strdup( (*it).latin1() );
86 int err = mailimf_address_list_add_parse( addresses, str );
87 if ( err != MAILIMF_NO_ERROR ) {
88 qDebug( "Error parsing" );
89 qDebug( *it );
90 free( str );
91 } else {
92 qDebug( "Parse success! :)" );
93 }
94 }
95
96 return addresses;
97}
98
99mailimf_fields *SMTPwrapper::createImfFields(const Mail&mail )
100{
101 mailimf_fields *fields;
102 mailimf_field *xmailer;
103 mailimf_mailbox *sender, *fromBox;
104 mailimf_mailbox_list *from;
105 mailimf_address_list *to, *cc, *bcc, *reply;
106 char *subject = strdup( mail.getSubject().latin1() );
107 int err;
108
109 sender = newMailbox( mail.getName(), mail.getMail() );
110 if ( sender == NULL ) goto err_free;
111
112 fromBox = newMailbox( mail.getName(), mail.getMail() );
113 if ( fromBox == NULL ) goto err_free_sender;
114
115 from = mailimf_mailbox_list_new_empty();
116 if ( from == NULL ) goto err_free_fromBox;
117
118 err = mailimf_mailbox_list_add( from, fromBox );
119 if ( err != MAILIMF_NO_ERROR ) goto err_free_from;
120
121 to = parseAddresses( mail.getTo() );
122 if ( to == NULL ) goto err_free_from;
123
124 cc = parseAddresses( mail.getCC() );
125 bcc = parseAddresses( mail.getBCC() );
126 reply = parseAddresses( mail.getReply() );
127
128 fields = mailimf_fields_new_with_data( from, sender, reply, to, cc, bcc,
129 NULL, NULL, subject );
130 if ( fields == NULL ) goto err_free_reply;
131
132 xmailer = mailimf_field_new_custom( strdup( "User-Agent" ),
133 strdup( USER_AGENT ) );
134 if ( xmailer == NULL ) goto err_free_fields;
135
136 err = mailimf_fields_add( fields, xmailer );
137 if ( err != MAILIMF_NO_ERROR ) goto err_free_xmailer;
138
139 return fields; // Success :)
140
141err_free_xmailer:
142 mailimf_field_free( xmailer );
143err_free_fields:
144 mailimf_fields_free( fields );
145err_free_reply:
146 mailimf_address_list_free( reply );
147 mailimf_address_list_free( bcc );
148 mailimf_address_list_free( cc );
149 mailimf_address_list_free( to );
150err_free_from:
151 mailimf_mailbox_list_free( from );
152err_free_fromBox:
153 mailimf_mailbox_free( fromBox );
154err_free_sender:
155 mailimf_mailbox_free( sender );
156err_free:
157 free( subject );
158 qDebug( "createImfFields - error" );
159
160 return NULL; // Error :(
161}
162
163mailmime *SMTPwrapper::buildTxtPart(const QString&str )
164{
165 mailmime *txtPart;
166 mailmime_fields *fields;
167 mailmime_content *content;
168 mailmime_parameter *param;
169 char *txt = strdup( str.latin1() );
170 int err;
171
172 param = mailmime_parameter_new( strdup( "charset" ),
173 strdup( "iso-8859-1" ) );
174 if ( param == NULL ) goto err_free;
175
176 content = mailmime_content_new_with_str( "text/plain" );
177 if ( content == NULL ) goto err_free_param;
178
179 err = clist_append( content->ct_parameters, param );
180 if ( err != MAILIMF_NO_ERROR ) goto err_free_content;
181
182 fields = mailmime_fields_new_encoding( MAILMIME_MECHANISM_8BIT );
183 if ( fields == NULL ) goto err_free_content;
184
185 txtPart = mailmime_new_empty( content, fields );
186 if ( txtPart == NULL ) goto err_free_fields;
187
188 err = mailmime_set_body_text( txtPart, txt, strlen( txt ) );
189 if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart;
190
191 return txtPart; // Success :)
192
193err_free_txtPart:
194 mailmime_free( txtPart );
195err_free_fields:
196 mailmime_fields_free( fields );
197err_free_content:
198 mailmime_content_free( content );
199err_free_param:
200 mailmime_parameter_free( param );
201err_free:
202 free( txt );
203 qDebug( "buildTxtPart - error" );
204
205 return NULL; // Error :(
206}
207
208mailmime *SMTPwrapper::buildFilePart(const QString&filename,const QString&mimetype )
209{
210 mailmime * filePart;
211 mailmime_fields * fields;
212 mailmime_content * content;
213 mailmime_parameter * param = NULL;
214 int err;
215
216 int pos = filename.findRev( '/' );
217 QString tmp = filename.right( filename.length() - ( pos + 1 ) );
218 char *name = strdup( tmp.latin1() ); // just filename
219 char *file = strdup( filename.latin1() ); // full name with path
220 char *mime = strdup( mimetype.latin1() ); // mimetype -e.g. text/plain
221
222 fields = mailmime_fields_new_filename(
223 MAILMIME_DISPOSITION_TYPE_ATTACHMENT, name,
224 MAILMIME_MECHANISM_BASE64 );
225 if ( fields == NULL ) goto err_free;
226
227 content = mailmime_content_new_with_str( mime );
228 if ( content == NULL ) goto err_free_fields;
229
230 if ( mimetype.compare( "text/plain" ) == 0 ) {
231 param = mailmime_parameter_new( strdup( "charset" ),
232 strdup( "iso-8859-1" ) );
233 if ( param == NULL ) goto err_free_content;
234
235 err = clist_append( content->ct_parameters, param );
236 if ( err != MAILIMF_NO_ERROR ) goto err_free_param;
237 }
238
239 filePart = mailmime_new_empty( content, fields );
240 if ( filePart == NULL ) goto err_free_param;
241
242 err = mailmime_set_body_file( filePart, file );
243 if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart;
244
245 return filePart; // Success :)
246
247err_free_filePart:
248 mailmime_free( filePart );
249err_free_param:
250 if ( param != NULL ) mailmime_parameter_free( param );
251err_free_content:
252 mailmime_content_free( content );
253err_free_fields:
254 mailmime_fields_free( fields );
255err_free:
256 free( name );
257 free( mime );
258 free( file );
259 qDebug( "buildFilePart - error" );
260
261 return NULL; // Error :(
262}
263
264void SMTPwrapper::addFileParts( mailmime *message,const QList<Attachment>&files )
265{
266 const Attachment *it;
267 /* work around for the brainfucked qlist which can not act with const values */
268 for ( it = ((QList<Attachment>)files).first(); it; it = ((QList<Attachment>)files).next() ) {
269 qDebug( "Adding file" );
270 mailmime *filePart;
271 int err;
272
273 filePart = buildFilePart( it->getFileName(), it->getMimeType() );
274 if ( filePart == NULL ) goto err_free;
275
276 err = mailmime_smart_add_part( message, filePart );
277 if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart;
278
279 continue; // Success :)
280
281 err_free_filePart:
282 mailmime_free( filePart );
283 err_free:
284 qDebug( "addFileParts: error adding file:" );
285 qDebug( it->getFileName() );
286 }
287}
288
289mailmime *SMTPwrapper::createMimeMail(const Mail &mail )
290{
291 mailmime *message, *txtPart;
292 mailimf_fields *fields;
293 int err;
294
295 fields = createImfFields( mail );
296 if ( fields == NULL ) goto err_free;
297
298 message = mailmime_new_message_data( NULL );
299 if ( message == NULL ) goto err_free_fields;
300
301 mailmime_set_imf_fields( message, fields );
302
303 txtPart = buildTxtPart( mail.getMessage() );
304 if ( txtPart == NULL ) goto err_free_message;
305
306 err = mailmime_smart_add_part( message, txtPart );
307 if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart;
308
309 addFileParts( message, mail.getAttachments() );
310
311 return message; // Success :)
312
313err_free_txtPart:
314 mailmime_free( txtPart );
315err_free_message:
316 mailmime_free( message );
317err_free_fields:
318 mailimf_fields_free( fields );
319err_free:
320 qDebug( "createMimeMail: error" );
321
322 return NULL; // Error :(
323}
324
325mailimf_field *SMTPwrapper::getField( mailimf_fields *fields, int type )
326{
327 mailimf_field *field;
328 clistiter *it;
329
330 it = clist_begin( fields->fld_list );
331 while ( it ) {
332 field = (mailimf_field *) it->data;
333 if ( field->fld_type == type ) {
334 return field;
335 }
336 it = it->next;
337 }
338
339 return NULL;
340}
341
342void SMTPwrapper::addRcpts( clist *list, mailimf_address_list *addr_list )
343{
344 clistiter *it, *it2;
345
346 for ( it = clist_begin( addr_list->ad_list ); it; it = it->next ) {
347 mailimf_address *addr;
348 addr = (mailimf_address *) it->data;
349
350 if ( addr->ad_type == MAILIMF_ADDRESS_MAILBOX ) {
351 esmtp_address_list_add( list, addr->ad_data.ad_mailbox->mb_addr_spec, 0, NULL );
352 } else if ( addr->ad_type == MAILIMF_ADDRESS_GROUP ) {
353 clist *l = addr->ad_data.ad_group->grp_mb_list->mb_list;
354 for ( it2 = clist_begin( l ); it2; it2 = it2->next ) {
355 mailimf_mailbox *mbox;
356 mbox = (mailimf_mailbox *) it2->data;
357 esmtp_address_list_add( list, mbox->mb_addr_spec, 0, NULL );
358 }
359 }
360 }
361}
362
363clist *SMTPwrapper::createRcptList( mailimf_fields *fields )
364{
365 clist *rcptList;
366 mailimf_field *field;
367
368 rcptList = esmtp_address_list_new();
369
370 field = getField( fields, MAILIMF_FIELD_TO );
371 if ( field && (field->fld_type == MAILIMF_FIELD_TO)
372 && field->fld_data.fld_to->to_addr_list ) {
373 addRcpts( rcptList, field->fld_data.fld_to->to_addr_list );
374 }
375
376 field = getField( fields, MAILIMF_FIELD_CC );
377 if ( field && (field->fld_type == MAILIMF_FIELD_CC)
378 && field->fld_data.fld_cc->cc_addr_list ) {
379 addRcpts( rcptList, field->fld_data.fld_cc->cc_addr_list );
380 }
381
382 field = getField( fields, MAILIMF_FIELD_BCC );
383 if ( field && (field->fld_type == MAILIMF_FIELD_BCC)
384 && field->fld_data.fld_bcc->bcc_addr_list ) {
385 addRcpts( rcptList, field->fld_data.fld_bcc->bcc_addr_list );
386 }
387
388 return rcptList;
389}
390
391char *SMTPwrapper::getFrom( mailmime *mail )
392{
393 char *from = NULL;
394
395 mailimf_field *ffrom;
396 ffrom = getField( mail->mm_data.mm_message.mm_fields, MAILIMF_FIELD_FROM );
397 if ( ffrom && (ffrom->fld_type == MAILIMF_FIELD_FROM)
398 && ffrom->fld_data.fld_from->frm_mb_list && ffrom->fld_data.fld_from->frm_mb_list->mb_list ) {
399 clist *cl = ffrom->fld_data.fld_from->frm_mb_list->mb_list;
400 clistiter *it;
401 for ( it = clist_begin( cl ); it; it = it->next ) {
402 mailimf_mailbox *mb = (mailimf_mailbox *) it->data;
403 from = strdup( mb->mb_addr_spec );
404 }
405 }
406
407 return from;
408}
409
410SMTPaccount *SMTPwrapper::getAccount(const QString&from )
411{
412 SMTPaccount *smtp;
413
414 QList<Account> list = settings->getAccounts();
415 Account *it;
416 for ( it = list.first(); it; it = list.next() ) {
417 if ( it->getType().compare( "SMTP" ) == 0 ) {
418 smtp = static_cast<SMTPaccount *>(it);
419 if ( smtp->getMail().compare( from ) == 0 ) {
420 qDebug( "SMTPaccount found for" );
421 qDebug( from );
422 return smtp;
423 }
424 }
425 }
426
427 return NULL;
428}
429
430QString SMTPwrapper::getTmpFile() {
431 int num = 0;
432 QString unique;
433
434 QDir dir( "/tmp" );
435 QStringList::Iterator it;
436
437 QStringList list = dir.entryList( "opiemail-tmp-*" );
438 do {
439 unique.setNum( num++ );
440 } while ( list.contains( "opiemail-tmp-" + unique ) > 0 );
441
442 return "/tmp/opiemail-tmp-" + unique;
443}
444
445void SMTPwrapper::writeToFile(const QString&file, mailmime *mail )
446{
447 FILE *f;
448 int err, col = 0;
449
450 f = fopen( file.latin1(), "w" );
451 if ( f == NULL ) {
452 qDebug( "writeToFile: error opening file" );
453 return;
454 }
455
456 err = mailmime_write( f, &col, mail );
457 if ( err != MAILIMF_NO_ERROR ) {
458 fclose( f );
459 qDebug( "writeToFile: error writing mailmime" );
460 return;
461 }
462
463 fclose( f );
464}
465
466void SMTPwrapper::readFromFile(const QString&file, char **data, size_t *size )
467{
468 char *buf;
469 struct stat st;
470 int fd, count = 0, total = 0;
471
472 fd = open( file.latin1(), O_RDONLY, 0 );
473 if ( fd == -1 ) return;
474
475 if ( fstat( fd, &st ) != 0 ) goto err_close;
476 if ( !st.st_size ) goto err_close;
477
478 buf = (char *) malloc( st.st_size );
479 if ( !buf ) goto err_close;
480
481 while ( ( total < st.st_size ) && ( count >= 0 ) ) {
482 count = read( fd, buf + total, st.st_size - total );
483 total += count;
484 }
485 if ( count < 0 ) goto err_free;
486
487 *data = buf;
488 *size = st.st_size;
489
490 close( fd );
491
492 return; // Success :)
493
494err_free:
495 free( buf );
496err_close:
497 close( fd );
498}
499
500void SMTPwrapper::progress( size_t current, size_t maximum )
501{
502 qDebug( "Current: %i of %i", current, maximum );
503}
504
505void SMTPwrapper::smtpSend( mailmime *mail )
506{
507 mailsmtp *session;
508 clist *rcpts;
509 char *from, *data, *server, *user = NULL, *pass = NULL;
510 size_t size;
511 int err;
512 bool ssl;
513 uint16_t port;
514
515
516 from = getFrom( mail );
517 SMTPaccount *smtp = getAccount( from );
518 if ( smtp == NULL ) {
519 free(from);
520 return;
521 }
522 server = strdup( smtp->getServer().latin1() );
523 ssl = smtp->getSSL();
524 port = smtp->getPort().toUInt();
525 rcpts = createRcptList( mail->mm_data.mm_message.mm_fields );
526
527 QString file = getTmpFile();
528 writeToFile( file, mail );
529 readFromFile( file, &data, &size );
530 QFile f( file );
531 f.remove();
532
533 session = mailsmtp_new( 20, &progress );
534 if ( session == NULL ) goto free_mem;
535
536 qDebug( "Servername %s at port %i", server, port );
537 if ( ssl ) {
538 qDebug( "SSL session" );
539 err = mailsmtp_ssl_connect( session, server, port );
540 } else {
541 qDebug( "No SSL session" );
542 err = mailsmtp_socket_connect( session, server, port );
543 }
544 if ( err != MAILSMTP_NO_ERROR ) goto free_mem_session;
545
546 err = mailsmtp_init( session );
547 if ( err != MAILSMTP_NO_ERROR ) goto free_con_session;
548
549 qDebug( "INIT OK" );
550
551 if ( smtp->getLogin() ) {
552 if ( smtp->getUser().isEmpty() || smtp->getPassword().isEmpty() ) {
553 // get'em
554 LoginDialog login( smtp->getUser(), smtp->getPassword(), NULL, 0, true );
555 login.show();
556 if ( QDialog::Accepted == login.exec() ) {
557 // ok
558 user = strdup( login.getUser().latin1() );
559 pass = strdup( login.getPassword().latin1() );
560 } else {
561 goto free_con_session;
562 }
563 } else {
564 user = strdup( smtp->getUser().latin1() );
565 pass = strdup( smtp->getPassword().latin1() );
566 }
567 qDebug( "session->auth: %i", session->auth);
568 err = mailsmtp_auth( session, user, pass );
569 if ( err == MAILSMTP_NO_ERROR ) qDebug("auth ok");
570 qDebug( "Done auth!" );
571 }
572
573 err = mailsmtp_send( session, from, rcpts, data, size );
574 if ( err != MAILSMTP_NO_ERROR ) goto free_con_session;
575
576 qDebug( "Mail sent." );
577
578free_con_session:
579 mailsmtp_quit( session );
580free_mem_session:
581 mailsmtp_free( session );
582free_mem:
583 smtp_address_list_free( rcpts );
584 free( data );
585 free( server );
586 if ( smtp->getLogin() ) {
587 free( user );
588 free( pass );
589 }
590 free( from );
591}
592
593void SMTPwrapper::sendMail(const Mail&mail )
594{
595 mailmime *mimeMail;
596
597 mimeMail = createMimeMail(mail );
598 if ( mimeMail == NULL ) {
599 qDebug( "sendMail: error creating mime mail" );
600 } else {
601 smtpSend( mimeMail );
602 mailmime_free( mimeMail );
603 }
604}