]> err.no Git - sope/commitdiff
added NGSendMail object
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Wed, 27 Oct 2004 13:14:04 +0000 (13:14 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Wed, 27 Oct 2004 13:14:04 +0000 (13:14 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@317 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-mime/ChangeLog
sope-mime/NGMail/ChangeLog
sope-mime/NGMail/GNUmakefile
sope-mime/NGMail/NGSendMail.h [new file with mode: 0644]
sope-mime/NGMail/NGSendMail.m [new file with mode: 0644]
sope-mime/NGMime/NGMimeFileData.h
sope-mime/NGMime/NGMimeFileData.m
sope-mime/Version

index 5b338749ced65f8269ae2c5c58caabd6c2fbb4a8..23d7a8ffa72f045862544a9bfdabb2f94da343b8 100644 (file)
@@ -1,3 +1,7 @@
+2004-10-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGMail: added NGSendMail object (v4.3.190)
+
 2004-10-08  Helge Hess  <helge.hess@opengroupware.org>
 
        * NGImap4: minor improvement in an error condition (v4.3.189)
index 903d363ca7460b3ae677621f9e325cc1d4b3283d..fe0616bf0946b29ac5bb436159fa9c96478ea1f4 100644 (file)
@@ -1,3 +1,8 @@
+2004-10-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * added new NGSendMail object (derived from mail-deliver command in
+         OGo Logic)
+
 2004-10-04  Marcus Mueller  <znek@mulle-kybernetik.com>
 
        * NGMail.xcode: updated to the current build version
index a3845bb54d452671bdd3628790f7804572114271..5f250f5f3e27e2c72dc2e7c4bf121d6b2fc7a63a 100644 (file)
@@ -24,6 +24,7 @@ NGMail_HEADER_FILES = \
        NGPop3Support.h         \
        NGSmtpClient.h          \
        NGSmtpSupport.h         \
+       NGSendMail.h            \
 
 NGMail_OBJC_FILES = \
        NGMail.m                \
@@ -38,6 +39,7 @@ NGMail_OBJC_FILES = \
        NGPop3Support.m         \
        NGSmtpClient.m          \
        NGSmtpSupport.m         \
+       NGSendMail.m            \
        \
        NGMimeMessageBodyGenerator.m            \
        NGMimeMessageMultipartBodyGenerator.m   \
diff --git a/sope-mime/NGMail/NGSendMail.h b/sope-mime/NGMail/NGSendMail.h
new file mode 100644 (file)
index 0000000..e4b5fb2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2004 SKYRIX Software AG
+
+  This file is part of OpenGroupware.org.
+
+  OGo is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with OGo; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#ifndef __LSMail_NGSendMail_H__
+#define __LSMail_NGSendMail_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGPart.h>
+
+/*
+  NGSendMail
+  
+  An interface to the local sendmail binary for deliverying mail.
+*/
+
+@class NSString, NSArray, NSData, NSException;
+
+@interface NGSendMail : NSObject
+{
+  NSString *executablePath;
+  BOOL isLoggingEnabled;
+  BOOL shouldOnlyUseMailboxName;
+}
+
++ (id)sharedSendMail;
+
+- (id)initWithExecutablePath:(NSString *)_path;
+
+/* accessors */
+
+- (NSString *)executablePath;
+
+- (BOOL)isSendLoggingEnabled;
+- (BOOL)shouldOnlyUseMailboxName;
+
+/* operations */
+
+- (BOOL)isSendMailAvailable;
+
+- (NSException *)sendMailAtPath:(NSString *)_path toRecipients:(NSArray *)_to
+  sender:(NSString *)_sender;
+- (NSException *)sendMimePart:(id<NGMimePart>)_pt toRecipients:(NSArray *)_to
+  sender:(NSString *)_sender;
+- (NSException *)sendMailData:(NSData *)_data toRecipients:(NSArray *)_to
+  sender:(NSString *)_sender;
+
+@end
+
+#endif /* __LSMail_NGSendMail_H__ */
diff --git a/sope-mime/NGMail/NGSendMail.m b/sope-mime/NGMail/NGSendMail.m
new file mode 100644 (file)
index 0000000..c379b4c
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+  Copyright (C) 2004 SKYRIX Software AG
+
+  This file is part of OpenGroupware.org.
+
+  OGo is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with OGo; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#include "NGSendMail.h"
+#include "NGMimeMessageGenerator.h"
+#include "NGMailAddressParser.h"
+#include "NGMailAddress.h"
+#include "common.h"
+
+// TODO: this class is derived from the LSMailDeliverCommand in OGo Logic,
+//       it still needs a lot of cleanup
+
+@implementation NGSendMail
+
++ (id)sharedSendMail {
+  static NGSendMail *sendmail = nil; // THREAD
+  if (sendmail == nil)
+    sendmail = [[self alloc] init];
+  return sendmail;
+}
+
+- (id)initWithExecutablePath:(NSString *)_path {
+  if ((self = [super init])) {
+    NSUserDefaults *ud;
+    
+    self->isLoggingEnabled = 
+      [ud boolForKey:@"ImapDebugEnabled"];
+    self->shouldOnlyUseMailboxName =
+      [ud boolForKey:@"UseOnlyMailboxNameForSendmail"];
+    
+    self->executablePath = 
+      [_path isNotNull] ? [_path copy] : @"/usr/lib/sendmail";
+  }
+  return self;
+}
+- (id)init {
+  NSString *p;
+  
+  p = [[NSUserDefaults standardUserDefaults] stringForKey:@"SendmailPath"];
+  return [self initWithExecutablePath:p];
+}
+
+- (void)dealloc {
+  [self->executablePath release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)executablePath {
+  return self->executablePath;
+}
+
+- (BOOL)isSendLoggingEnabled {
+  return self->isLoggingEnabled;
+}
+- (BOOL)shouldOnlyUseMailboxName {
+  return self->shouldOnlyUseMailboxName;
+}
+
+/* operations */
+
+- (BOOL)isSendMailAvailable {
+  NSFileManager *fm;
+  
+  fm = [NSFileManager defaultManager];
+  return [fm isExecutableFileAtPath:[self executablePath]];
+}
+
+/* errors */
+
+- (NSException *)missingMailToSendError {
+  return [NSException exceptionWithName:@"NGSendMailException"
+                     reason:@"missing mail content to send"
+                     userInfo:nil];
+}
+- (NSException *)cannotWriteTemporaryFileError {
+  return [NSException exceptionWithName:@"NGSendMailException"
+                     reason:@"failed to write temporary mail file"
+                     userInfo:nil];
+}
+- (NSException *)failedToStartSendMailError:(int)_errorCode {
+  return [NSException exceptionWithName:@"NGSendMailException"
+                     reason:@"failed to start sendmail tool"
+                     userInfo:nil];
+}
+- (NSException *)failedToSendFileToSendMail:(NSString *)_path {
+  return [NSException exceptionWithName:@"NGSendMailException"
+                     reason:@"failed to send message file to sendmail tool"
+                     userInfo:nil];
+}
+- (NSException *)failedToSendDataToSendMail:(NSData *)_data {
+  return [NSException exceptionWithName:@"NGSendMailException"
+                     reason:@"failed to send message data to sendmail tool"
+                     userInfo:nil];
+}
+
+- (NSException *)_errorExceptionWithReason:(NSString *)_reason {
+  return [NSException exceptionWithName:@"NGSendMailException"
+                     reason:_reason
+                     userInfo:nil];
+#if 0 // TODO: in LSMailDeliverCommand, check whether someone depends on it
+  return [LSDBObjectCommandException exceptionWithStatus:NO
+                                    object:self
+                                    reason:_reason userInfo:nil];
+#endif
+}
+
+- (NSException *)_handleSendMailErrorCode:(int)_ec sendmail:(NSString *)_cmdl {
+  if (_ec == 32512) {
+    NSString *str;
+    
+    str = [@"NoExecutableSendmailBinary " stringByAppendingString:
+             [self executablePath]];
+    [self logWithFormat:@"%@ is no executable file", [self executablePath]];
+    return [self _errorExceptionWithReason:str];
+  }
+  if (_ec == 17664) {
+    [self logWithFormat:@"sendmail: message file too big!"];
+    return [self _errorExceptionWithReason:@"MessageFileTooBig"];
+  }
+  
+  [self logWithFormat:@"[1] Could not write mail to sendmail! <%d>",_ec];
+  return [self _errorExceptionWithReason:@"FailedToSendMail"];
+}
+
+/* temporary file */
+
+- (void)_removeMailTmpFile:(NSString *)_path {
+  if ([_path length] < 2)
+    return;
+  
+  [[NSFileManager defaultManager] removeFileAtPath:_path handler:nil];
+}
+
+- (NSString *)_generateTemporaryFileForPart:(id<NGMimePart>)_part {
+  NGMimeMessageGenerator *gen;
+  NSString *p;
+  
+  gen = [[NGMimeMessageGenerator alloc] init];
+  p = [[gen generateMimeFromPartToFile:_part] copy];
+  [gen release]; gen = nil;
+
+  return [p autorelease];
+}
+
+/* parsing mail addresses */
+
+- (NSString *)mailAddrForStr:(NSString *)_str {
+  NGMailAddressParser *parser;
+  NGMailAddress       *addr;
+  
+  if (![self shouldOnlyUseMailboxName])
+    return _str;
+  
+  parser = nil;
+  addr   = nil;
+  
+  // TODO: make NGMailAddressParser not throw exceptions,
+  //       then remove the handler
+  NS_DURING {
+    parser = [NGMailAddressParser mailAddressParserWithString:_str];
+    addr   = [[parser parseAddressList] lastObject];
+  }
+  NS_HANDLER {
+    fprintf(stderr,"ERROR: get exception during parsing address %s\n",
+            [[localException description] cString]);
+    parser = nil;
+    addr   = nil;
+  }
+  NS_ENDHANDLER;
+
+  return (addr) ? [addr address] : _str;
+}
+
+/* logging */
+
+- (void)_logMailSend:(NSString *)sendmail ofPath:(NSString *)_p {
+  fprintf(stderr, "%s \n", [sendmail cString]);
+  fprintf(stderr, "read data from %s\n", [_p cString]);
+}
+
+- (void)_logMailSend:(NSString *)sendmail ofData:(NSData *)_data {
+  fprintf(stderr, "%s \n", [sendmail cString]);
+  
+  if ([_data length] > 5000) {
+    NSData *data;
+    
+    data = [_data subdataWithRange:NSMakeRange(0,5000)];
+    fprintf(stderr, "%s...\n", (unsigned char *)[data bytes]);
+  }
+  else
+    fprintf(stderr, "%s\n", (char *)[_data bytes]);
+}
+
+/* sending the mail */
+
+- (FILE *)openStreamToSendMail {
+  return popen([[self executablePath] cString], "w");
+}
+- (int)closeStreamToSendMail:(FILE *)_mail {
+  if (_mail == NULL) 
+    return 0;
+  return pclose(_mail);
+}
+
+- (NSMutableString *)buildSendMailCommandLineWithSender:(NSString *)_sender {
+  NSMutableString *sendmail;
+  
+  if ([[self executablePath] length] == 0)
+    return nil;
+  
+  sendmail = [NSMutableString stringWithCapacity:256];
+  [sendmail setString:[self executablePath]];
+  
+  /* don't treat a line with just "." as EOF */
+  [sendmail appendString:@" -i "];
+  
+  /* add sender when available */
+  if (_sender != nil) {
+    NSString *f;
+    
+    f = [[_sender componentsSeparatedByString:@","]
+                 componentsJoinedByString:@" "];
+    [sendmail appendString:@"-f "];
+    [sendmail appendString:f];
+    [sendmail appendString:@" "];
+  }
+  return sendmail;
+}
+
+- (NSException *)_handleAppendMessageException:(NSException *)_exception {
+  [self logWithFormat:@"catched exception: %@", _exception];
+  return nil;
+}
+
+- (BOOL)_appendMessageFile:(NSString *)_p to:(FILE *)_fd {
+  NGFileStream *fs;
+  int  fileLen;
+  BOOL result;
+
+  if (_p == nil) {
+    NSLog(@"ERROR: call %s without self->messageTmpFile",
+          __PRETTY_FUNCTION__);
+    return NO;
+  }
+  fileLen = [[[[NSFileManager defaultManager]
+                              fileAttributesAtPath:_p
+                              traverseLink:NO]
+                              objectForKey:NSFileSize] intValue];
+  
+  if (fileLen == 0) {
+    NSLog(@"ERROR[%s] missing file at path %@", __PRETTY_FUNCTION__,
+          _p);
+    return NO;
+  }
+  
+  fs = [(NGFileStream *)[NGFileStream alloc] initWithPath:_p];
+
+  if (![fs openInMode:@"r"]) {
+    NSLog(@"ERROR[%s]: could not open file stream for temp-file for "
+          @"reading: %@", __PRETTY_FUNCTION__, _p);
+    [fs release]; fs = nil;
+    return NO;
+  }
+  result = YES;
+  NS_DURING {
+    int  read;
+    int  alreadyRead;
+    int  bufCnt = 8192;
+    char buffer[bufCnt+1];
+
+    alreadyRead = 0;
+    
+    read = (bufCnt > (fileLen - alreadyRead))
+           ? fileLen - alreadyRead : bufCnt;
+        
+    while ((read = [fs readBytes:buffer count:read])) {
+        alreadyRead += read;
+
+        buffer[read] = '\0';
+
+        if (fputs(buffer, _fd) == EOF) {
+          fprintf(stderr, "%s: Failed to write %i bytes to process\n",
+                  __PRETTY_FUNCTION__, alreadyRead);
+          break;
+        }
+        if (alreadyRead == fileLen)
+          break;
+    }
+  }
+  NS_HANDLER {
+    [[self _handleAppendMessageException:localException] raise];
+    result = NO;
+  }
+  NS_ENDHANDLER;
+  
+  [fs release]; fs = nil;
+  return result;
+}
+
+- (BOOL)_appendData:(NSData *)_data to:(FILE *)_fd {
+  int written;
+  
+  if ([_data length] == 0)
+    return YES;
+  
+  written = fwrite((char *)[_data bytes], [_data length],
+                  1, _fd);
+  if (written > 0)
+    return YES;
+  
+  [self logWithFormat:@"[2] Could not write mail to sendmail <%d>", errno];
+  
+  if ([_data length] > 5000)
+    [self logWithFormat:@"[2] message: [size: %d]", [_data length]];
+  else
+    [self logWithFormat:@"[2] message: <%s>", (char *)[_data bytes]];
+  
+  return NO;
+}
+
+- (void)addRecipients:(NSArray *)_recipients 
+  toCmdLine:(NSMutableString *)_cmdline
+{
+  NSEnumerator *enumerator;
+  NSString     *str;
+  
+  enumerator = [_recipients objectEnumerator];
+  while ((str = [enumerator nextObject]) != nil) {
+    NSEnumerator *e;
+    NSString     *s;
+    
+    if ([str rangeOfString:@","].length == 0) {
+      [_cmdline appendFormat:@"'%@' ", [self mailAddrForStr:str]];
+      continue;
+    }
+    
+    e = [[str componentsSeparatedByString:@","] objectEnumerator];
+    while ((s = [e nextObject])) {
+      s = [[s componentsSeparatedByString:@"'"] componentsJoinedByString:@""];
+      s = [[s componentsSeparatedByString:@","] componentsJoinedByString:@""];
+      
+      [_cmdline appendFormat:@"'%@'", [self mailAddrForStr:s]];
+    }
+    [_cmdline appendString:@" "];
+  }
+}
+
+/* main entry methods */
+
+- (NSException *)sendMailAtPath:(NSString *)_path toRecipients:(NSArray *)_to
+  sender:(NSString *)_sender
+{
+  NSMutableString *sendmail;
+  FILE            *toMail       = NULL;
+  NSException     *error;
+  int  errorCode;
+  BOOL ok;
+  
+  if (_path == nil)
+    return [self missingMailToSendError];
+  
+  sendmail = [self buildSendMailCommandLineWithSender:_sender];
+  [self addRecipients:_to toCmdLine:sendmail];
+  
+  if ((toMail = [self openStreamToSendMail]) == NULL)
+    return [self failedToStartSendMailError:errno];
+  
+  if ([self isSendLoggingEnabled]) [self _logMailSend:sendmail ofPath:_path];
+  
+  ok = [self _appendMessageFile:_path to:toMail];
+  
+  error = nil;
+  if ((errorCode = [self closeStreamToSendMail:toMail]) != 0) {
+    if (ok) {
+      error = [self _handleSendMailErrorCode:errorCode sendmail:sendmail];
+    }
+  }
+  if (!ok) error = [self failedToSendFileToSendMail:_path];
+  return error; /* nil means 'everything is awesome' */
+}
+
+- (NSException *)sendMailData:(NSData *)_data toRecipients:(NSArray *)_to
+  sender:(NSString *)_sender
+{
+  NSMutableString *sendmail;
+  FILE            *toMail       = NULL;
+  NSException     *error;
+  int  errorCode;
+  BOOL ok;
+  
+  if (_data == nil)
+    return [self missingMailToSendError];
+  
+  sendmail = [self buildSendMailCommandLineWithSender:_sender];
+  [self addRecipients:_to toCmdLine:sendmail];
+  
+  if ((toMail = [self openStreamToSendMail]) == NULL)
+    return [self failedToStartSendMailError:errno];
+  
+  if ([self isSendLoggingEnabled]) [self _logMailSend:sendmail ofData:_data];
+  
+  ok = [self _appendData:_data to:toMail];
+  
+  error = nil;
+  if ((errorCode = [self closeStreamToSendMail:toMail]) != 0) {
+    if (ok) {
+      error = [self _handleSendMailErrorCode:errorCode sendmail:sendmail];
+    }
+  }
+  if (!ok) error = [self failedToSendDataToSendMail:_data];
+  return error; /* nil means 'everything is awesome' */
+}
+
+- (NSException *)sendMimePart:(id<NGMimePart>)_pt toRecipients:(NSArray *)_to
+  sender:(NSString *)_sender
+{
+  NSException *error;
+  NSString *tmpfile;
+  
+  if (_pt == nil)
+    return [self missingMailToSendError];
+
+  /* generate file for part */
+  
+  if ((tmpfile = [self _generateTemporaryFileForPart:_pt]) == nil)
+    return [self cannotWriteTemporaryFileError];
+
+  /* send file */
+  
+  error = [self sendMailAtPath:tmpfile toRecipients:_to sender:_sender];
+  
+  /* delete temporary file */
+  
+  [self _removeMailTmpFile:tmpfile];
+  
+  return error;
+}
+
+@end /* NGSendMail */
index 1f92abf872707d375a97d142e29489d83dbc966f..1142314e8c7e26c7ee8b552928eefb4e770b9294 100644 (file)
@@ -1,7 +1,7 @@
 /*
-  Copyright (C) 2000-2003 SKYRIX Software AG
+  Copyright (C) 2000-2004 SKYRIX Software AG
 
-  This file is part of OGo
+  This file is part of OpenGroupware.org.
 
   OGo is free software; you can redistribute it and/or modify it under
   the terms of the GNU Lesser General Public License as published by the
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #ifndef __NGMime_NGMimeFileData_H__
 #define __NGMime_NGMimeFileData_H__
 
 #import <Foundation/NSData.h>
 
+/*
+  NGMimeFileData
+  
+  TODO: explain. Somehow this is an object to save loading an NSData to RAM.
+  
+  Checked in:
+  - NGMimeBodyGenerator
+  - NGMimeBodyPart
+  - NGMimeJoinedData
+*/
+
 @class NSString;
 
 @interface NGMimeFileData : NSData
   int      length;
 }
 
-
 - (id)initWithPath:(NSString *)_path removeFile:(BOOL)_remove;
 
+/* operations */
+
 - (BOOL)appendDataToFileDesc:(int)_fd;
 
 @end /* NGMimeFileData */
index 62150d9608fcb5d54bcf8ef3f87d439311fc312b..5745b4961ba3d75a82560cde07fc63146ad4d857 100644 (file)
@@ -18,7 +18,6 @@
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #include "NGMimeFileData.h"
 #include "common.h"
@@ -115,11 +114,6 @@ static unsigned      tmpmask  = 0600;
   return self->length;
 }
 
-- (NSString *)description {
-  return [NSString stringWithFormat:@"<0x%08X[%@]: path=%@>",
-                     self, NSStringFromClass([self class]), self->path];
-}
-
 - (BOOL)appendDataToFileDesc:(int)_fd {
   NGFileStream *fs;
   int  bufCnt = 8192;
@@ -177,4 +171,11 @@ static unsigned      tmpmask  = 0600;
   return result;
 }
 
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: path=%@>",
+                     self, NSStringFromClass([self class]), self->path];
+}
+
 @end /* NGMimeFileData */
index 1c4ffc5e02d5e746e5e0ad339a2b4c56acd53376..af2f5a3fdf0807ec38192c4c2a9b4b5ae302c980 100644 (file)
@@ -2,6 +2,6 @@
 
 MAJOR_VERSION:=4
 MINOR_VERSION:=3
-SUBMINOR_VERSION:=189
+SUBMINOR_VERSION:=190
 
 # v4.2.149 requires libNGStreams v4.2.34