Files
MailCore/Source/CTSMTPAsyncConnection.m
T
jils 2f7f6acf61 Minor cleanup
--HG--
branch : KJ-1.0
2010-05-26 02:16:04 -07:00

268 lines
6.9 KiB
Objective-C

//
// CTSMTPAsyncConnection.m
// MailCore
//
// Created by Juan Leon on 5/6/10.
// Copyright 2010 NotOptimal.net. All rights reserved.
//
#import <libetpan/libetpan.h>
#import "CTCoreAddress.h"
#import "CTCoreMessage.h"
#import "CTESMTP.h"
#import "CTSMTP.h"
#import "CTSMTPAsyncConnection.h"
//setup to allow c callback fxn:
CTSMTPAsyncConnection* ptrToSelf;
void
smtpProgress( size_t aCurrent, size_t aTotal )
{
if( ptrToSelf != nil )
{
float theProgress = (float)aCurrent / (float)aTotal * 100;
[ptrToSelf performSelector:@selector(handleSmtpProgress:)
withObject:[NSNumber numberWithFloat:theProgress]];
}
}
@interface CTSMTPAsyncConnection (PrivateMethods)
- (void)sendMailThread;
- (void)handleSmtpProgress:(NSNumber*)aProgress;
- (void)threadWillExitHandler:(NSNotification*)aNote;
- (void)cleanupAfterThread;
@end
@implementation CTSMTPAsyncConnection
@synthesize message = mMessage;
@synthesize serverSettings = mServerSettings;
@synthesize status = mStatus;
- (id)initWithServer:(NSString *)aServer
username:(NSString *)aUsername
password:(NSString *)aPassword
port:(unsigned int)aPort
useTLS:(BOOL)aTls
useAuth:(BOOL)aAuth
delegate:(id<CTSMTPConnectionDelegate>)aDelegate
{
self = [super init];
if(self)
{
mStatus = CTSMTPAsyncSuccess;
ptrToSelf = self;
mSMTPObj = nil;
mSMTP = NULL;
mMailThread = nil;
mDelegate = aDelegate;
mServerSettings =
[[NSDictionary dictionaryWithObjectsAndKeys:aServer, @"server",
aUsername, @"username",
aPassword, @"password",
[NSNumber numberWithInt:aPort], @"port",
[NSNumber numberWithBool:aTls], @"tls",
[NSNumber numberWithBool:aAuth], @"auth", nil] retain];
//save clients from themselves (they could be leaking us - no dealloc)
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(threadWillExitHandler:)
name:NSThreadWillExitNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self cleanupAfterThread];
[super dealloc];
}
- (void)finalize
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self cleanupAfterThread];
[super finalize];
}
- (void)sendMessageInBackgroundAndNotify:(CTCoreMessage*)aMessage
{
//TODO: convert to exceptions?
if( aMessage == nil )
{
NSLog(@"CTCoreMessage param cannot be nil");
return;
}
if ( mMailThread != nil && [mMailThread isExecuting] )
{
NSLog(@"Can only send one message at a time, we're busy, sheesh.");
return;
}
NSAssert( mMailThread == nil, @"Invalid smtp thread state" );
self.message = aMessage;
//start thread:
mMailThread = [NSThread alloc];
[mMailThread initWithTarget:self selector:@selector(sendMailThread) object:nil];
[mMailThread start];
}
- (void)cancel
{
if( ![mMailThread isExecuting] || [mMailThread isCancelled] )
{
return;
}
//mark thread as cancelled
[mMailThread cancel];
//cancel libetpan smtp stream
mailstream_cancel(mSMTP->stream);
mailstream_close(mSMTP->stream);
mSMTP->stream = NULL;
mailsmtp_free(mSMTP);
mSMTP = NULL;
}
- (BOOL)isBusy
{
return ( mMailThread != nil && [mMailThread isExecuting] );
}
@end
@implementation CTSMTPAsyncConnection (PrivateMethods)
- (void)sendMailThread
{
NSAutoreleasePool* thePool = [[NSAutoreleasePool alloc] init];
void (*progFxn)(size_t, size_t) = &smtpProgress;
mSMTP = NULL;
mSMTP = mailsmtp_new(30, progFxn);
assert(mSMTP != NULL);
mSMTPObj = [[CTESMTP alloc] initWithResource:mSMTP];
NSDictionary* theSettings = self.serverSettings;
@try
{
[mSMTPObj connectToServer:[theSettings objectForKey:@"server"]
port:[[theSettings objectForKey:@"port"] unsignedIntValue]];
if ([mSMTPObj helo] == false) {
/* The server didn't support ESMTP, so switching to STMP */
[mSMTPObj release];
mSMTPObj = [[CTSMTP alloc] initWithResource:mSMTP];
[mSMTPObj helo];
}
if ([(NSNumber*)[theSettings objectForKey:@"tls"] boolValue] )
[mSMTPObj startTLS];
if ([(NSNumber*)[theSettings objectForKey:@"auth"] boolValue])
[mSMTPObj authenticateWithUsername:[theSettings objectForKey:@"username"]
password:[theSettings objectForKey:@"password"]
server:[theSettings objectForKey:@"server"]];
CTCoreMessage* theMessage = self.message;
[mSMTPObj setFrom:[[[theMessage from] anyObject] email]];
NSMutableSet *rcpts = [NSMutableSet set];
[rcpts unionSet:[theMessage to]];
[rcpts unionSet:[theMessage bcc]];
[rcpts unionSet:[theMessage cc]];
[mSMTPObj setRecipients:rcpts];
//send
int theReturn = [mSMTPObj setData:[theMessage render] raiseExceptions:NO];
if( theReturn == MAILSMTP_NO_ERROR )
{
mStatus = CTSMTPAsyncSuccess;
}
else if( theReturn == MAILSMTP_ERROR_STREAM && [mMailThread isCancelled] )
{
//libetpan was cancelled from another thread
mStatus = CTSMTPAsyncCanceled;
}
else
{
mStatus = CTSMTPAsyncError;
}
}
@catch (NSException* aException)
{
mStatus = CTSMTPAsyncError;
}
[thePool drain];
}
- (void)handleSmtpProgress:(NSNumber*)aProgress
{
//check if cancelled before sending an update
if( [mMailThread isCancelled] && [NSThread currentThread] == mMailThread )
{
return;
}
unsigned int theProgress = [aProgress unsignedIntValue];
if( theProgress > mLastProgress )
{
mLastProgress = theProgress;
//call delegate
if( mDelegate )
{
[mDelegate smtpProgress:mLastProgress];
}
}
}
- (void)threadWillExitHandler:(NSNotification*)aNote
{
if( [aNote object] != mMailThread )
{
return;
}
if( mDelegate )
{
[mDelegate smtpDidFinishSendingMessage:mStatus];
}
[self cleanupAfterThread];
}
- (void)cleanupAfterThread
{
[mSMTPObj release];
mSMTPObj = nil;
if( mSMTP )
{
mailstream_cancel(mSMTP->stream);
mailstream_close(mSMTP->stream);
mSMTP->stream = NULL;
mailsmtp_free(mSMTP);
mSMTP = NULL;
}
[mServerSettings release];
mServerSettings = nil;
[mMessage release];
mMessage = nil;
[mMailThread release];
mMailThread = nil;
}
@end