(1) -[EDSMTPStream _pathFromAddress:] is simplistic. We had problems with some mail server software (not sendmail, postfix or exim: take a guess). We were seeing 'From:' values like '"me" <me@example.com>', and this method was causing '<"me" <me@example.com>>' to be emitted in MAIL FROM or RCPT TO exchanges. We patched this:
- Code: Select all
- (NSString *)_pathFromAddress:(NSString *)address
{
NSString *path;
if ([address hasPrefix:@"<"] == NO) {
NSRange range1;
NSRange range2;
range1 = [address rangeOfString:@"<"];
range2 = [address rangeOfString:@">"];
if (range1.length && range2.length && range1.location < range2.location) {
range1.length = range2.length + range2.location - range1.location;
path = [address substringWithRange:range1];
} else {
path = [NSString stringWithFormat:@"<%@>", address];
}
} else {
path = address;
}
return path;
}
(2) In EDIPSocket, we can set socket timeouts, but not read them. A long time ago, I added this:
- Code: Select all
//---------------------------------------------------------------------------------------
// EDIPSocket-OSPExtensions.h created by patrickx on Mon 08-Mar-2004
//---------------------------------------------------------------------------------------
#import <EDCommon/EDIPSocket.h>
@interface EDIPSocket (OSPExtensions)
- (NSTimeInterval)sendTimeout;
- (NSTimeInterval)receiveTimeout;
@end
- Code: Select all
//---------------------------------------------------------------------------------------
// EDIPSocket-OSPExtensions.m created by patrickx on Mon 08-Mar-2004
//---------------------------------------------------------------------------------------
#import <Foundation/Foundation.h>
#ifndef EDCOMMON_OSXBUILD
#define EDCOMMON_OSXBUILD 1
#import <EDCommon/osdep.h>
#endif
#import "EDIPSocket-OSPExtensions.h"
#ifdef WIN32
#define EDSOCKETHANDLE ((int)[self nativeHandle])
#else
#define EDSOCKETHANDLE [self fileDescriptor]
#endif
//---------------------------------------------------------------------------------------
@implementation EDIPSocket (OSPExtensions)
//---------------------------------------------------------------------------------------
/*" Gets the socket option described by %anOption on protocol level %aLevel in %valueP. "*/
- (void)getSocketOption:(int)anOption level:(int)aLevel value:(void*)valueP valueLen:(int*)valueLenP {
if (getsockopt(EDSOCKETHANDLE, aLevel, anOption, (char *)valueP, valueLenP) == -1)
[NSException raise:NSFileHandleOperationException format:@"Failed to get option %d on socket: %s", anOption, strerror(ED_ERRNO)];
}
/*" Gets the socket option described by %anOption on protocol level %aLevel in %timeoutP. "*/
- (void)getSocketOption:(int)anOption level:(int)aLevel timeInterval:(NSTimeInterval*)timeoutP {
#if defined(WIN32)
int _timeout;
if(setsockopt(EDSOCKETHANDLE, aLevel, anOption, (char *)&_timeout, sizeof(_timeout)) == -1) {
[NSException raise:NSFileHandleOperationException format:@"Failed to get option %d on socket: %s", anOption, strerror(ED_ERRNO)];
} else {
*timeoutP = _timeout/1000.0;
}
#else
struct timeval _timeout;
int _timeoutLen = sizeof(_timeout);
if(getsockopt(EDSOCKETHANDLE, aLevel, anOption, &_timeout, &_timeoutLen) == -1) {
[NSException raise:NSFileHandleOperationException format:@"Failed to get option %d on socket: %s", anOption, strerror(ED_ERRNO)];
} else {
*timeoutP = _timeout.tv_sec + (1000000.0*_timeout.tv_usec);
}
#endif
}
/*" Gets the timeout for send (write) operations. This corresponds to !{SO_SNDTIMEO}. "*/
- (NSTimeInterval)sendTimeout {
NSTimeInterval aTimeoutVal;
[self getSocketOption:SO_SNDTIMEO level:SOL_SOCKET timeInterval:&aTimeoutVal];
return aTimeoutVal;
}
/*" gets the timeout for receive (read) operations. This corresponds to !{SO_RCVTIMEO}. "*/
- (NSTimeInterval)receiveTimeout {
NSTimeInterval aTimeoutVal;
[self getSocketOption:SO_RCVTIMEO level:SOL_SOCKET timeInterval:&aTimeoutVal];
return aTimeoutVal;
}
//---------------------------------------------------------------------------------------
@end
//---------------------------------------------------------------------------------------
(3) SMTP server timeouts. We saw those. So we overrode -[EDStream availableLine] in EDSMTPStream.
- Code: Select all
//---------------------------------------------------------------------------------------
// EDSMTPStream-OSPExtensions.h created by patrickx on Mon 08-Mar-2004
//---------------------------------------------------------------------------------------
#import <EDMessage/EDSMTPStream.h>
@interface EDSMTPStream (OSPExtensions)
@end
EDMESSAGE_EXTERN NSString *EDMessageTimeoutException;
- Code: Select all
//---------------------------------------------------------------------------------------
// EDSMTPStream-OSPExtensions.m created by patrickx on Mon 08-Mar-2004
//---------------------------------------------------------------------------------------
#import <Foundation/Foundation.h>
#import <EDCommon/EDTCPSocket.h>
#import "EDSMTPStream-OSPExtensions.h"
#import "EDIPSocket-OSPExtensions.h"
//---------------------------------------------------------------------------------------
@implementation EDSMTPStream (OSPExtensions)
//---------------------------------------------------------------------------------------
NSString *EDMessageTimeoutException = @"EDMessageTimeoutException";
//---------------------------------------------------------------------------------------
// overrides
//---------------------------------------------------------------------------------------
- (NSString *)availableLine {
NSString *returnValue = nil;
EDTCPSocket *socket = (EDTCPSocket*)[self fileHandle];
NSTimeInterval receiveTimeout = [socket receiveTimeout];
if (receiveTimeout > 0.0) {
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval stop;
returnValue = [super availableLine];
stop = [NSDate timeIntervalSinceReferenceDate];
if ((stop-start) > receiveTimeout) {
[NSException raise:EDMessageTimeoutException format:@"-[%@ %@]: %s:%d timed out after %.3fs",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), __FILE__, __LINE__, (stop-start)];
}
} else {
returnValue = [super availableLine];
}
return returnValue;
}
//---------------------------------------------------------------------------------------
@end
//---------------------------------------------------------------------------------------
(4) how do we file a copy of an email that we are about to send?
There is convenience API -[EDMailAgent sendMessage:], -[EDMailAgent sendMailWithHeaders:body:andAttachments:], etc. There isn't, or at least I couldn't identify, convenience API equivalent to -[EDMailAgent sendMailWithHeaders:body:andAttachments:] which assembles an EDInternetMessage and returns it (so that you could call -transferData) instead of sending it. It's easy enough to create one by refactoring -[EDMailAgent sendMailWithHeaders:body:andAttachments:].