EDCommon/EDMessage: some ancient patches and commentary

Discussion of the EDMessage and EDCommon frameworks.

EDCommon/EDMessage: some ancient patches and commentary

Postby patrick » 29 Sep 2011, 16:24

EDCommon/EDMessage: some ancient patches and commentary

(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:].
patrick
 
Posts: 2
Joined: 29 Sep 2011, 12:04

Return to ED Frameworks