From 929b170849c527c641ae1d3b92b78e0aa364f8a5 Mon Sep 17 00:00:00 2001 From: wolfgang Date: Thu, 9 Aug 2007 21:01:44 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1146 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 19 ++ NEWS | 2 + .../Appointments/SOGoCalendarComponent.m | 21 +- SoObjects/Appointments/SOGoTaskObject.m | 14 +- SoObjects/Mailer/SOGoDraftObject.h | 25 +- SoObjects/Mailer/SOGoDraftObject.m | 62 +---- SoObjects/Mailer/SOGoMailBaseObject.h | 4 + SoObjects/SOGo/GNUmakefile | 2 + SoObjects/SOGo/NSString+Utilities.h | 3 + SoObjects/SOGo/NSString+Utilities.m | 19 ++ SoObjects/SOGo/SOGoMailer.h | 50 ++++ SoObjects/SOGo/SOGoMailer.m | 256 ++++++++++++++++++ UI/MailerUI/UIxMailAccountActions.m | 3 + UI/MailerUI/UIxMailFolderActions.m | 2 +- UI/SOGoUI/SOGoACLAdvisory.m | 8 +- UI/WebServerResources/MailerUI.js | 2 +- 16 files changed, 402 insertions(+), 90 deletions(-) create mode 100644 SoObjects/SOGo/SOGoMailer.h create mode 100644 SoObjects/SOGo/SOGoMailer.m diff --git a/ChangeLog b/ChangeLog index 3cb83431..c9653a6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,24 @@ +2007-08-09 Wolfgang Sourdeau + + * SoObjects/SOGo/NSString+Utilities.m ([NSString + -pureEMailAddress]): new utility method inspired by the + "_rawSender" private method in SOGoDraftObject, which it now + replaces. + + * SoObjects/SOGo/SOGoMailer.m: new abstraction class module that + provides a common API for sending emails, no matter what the + transport is. + 2007-08-08 Wolfgang Sourdeau + * UI/MailerUI/UIxMailFolderActions.m ([UIxMailFolderActions + -quotasAction]): invoke "relativeImap4Name" instead of + "nameInContainer" since the latter also returns the "folder" + prefix. + + * UI/MailerUI/UIxMailAccountActions.m ([UIxMailAccountActions + -listMailboxesAction]): declare the output as text/plain in UTF-8. + * UI/MailerUI/UIxMailFolderActions.m ([UIxMailFolderActions -deleteFolderAction]): fixed the url of the destination folder. diff --git a/NEWS b/NEWS index b4726756..3c5dfca9 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ - fixed a bug where folders starting with digits would not be displayed; - improved IE7 and Safari support: priority menus, attendees selector; - added the ability to print messages from the mailer toolbar; +- added the ability to use and configure SMTP as the email transport instead + of sendmail; 0.9.0-20070713 -------------- diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 50e2c475..808275d3 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -21,20 +21,24 @@ */ #import +#import #import #import #import #import +#import +#import #import #import #import -#import -#import -#import +#import +#import +#import #import #import +#import #import #import #import @@ -332,7 +336,6 @@ static BOOL sendEMailNotifications = NO; NSString *pageName; iCalPerson *organizer; NSString *cn, *email, *sender, *iCalString; - NGSendMail *sendmail; WOApplication *app; unsigned i, count; iCalPerson *attendee; @@ -360,9 +363,6 @@ static BOOL sendEMailNotifications = NO; /* generate iCalString once */ iCalString = [[_newObject parent] versitString]; - /* get sendmail object */ - sendmail = [NGSendMail sharedSendMail]; - /* get WOApplication instance */ app = [WOApplication application]; @@ -444,9 +444,10 @@ static BOOL sendEMailNotifications = NO; [body release]; /* send the damn thing */ - [sendmail sendMimePart: msg - toRecipients: [NSArray arrayWithObject: email] - sender: [organizer rfc822Email]]; + [[SOGoMailer sharedMailer] + sendMimePart: msg + toRecipients: [NSArray arrayWithObject: email] + sender: [organizer rfc822Email]]; } } } diff --git a/SoObjects/Appointments/SOGoTaskObject.m b/SoObjects/Appointments/SOGoTaskObject.m index 5fc7b15a..ac3b241c 100644 --- a/SoObjects/Appointments/SOGoTaskObject.m +++ b/SoObjects/Appointments/SOGoTaskObject.m @@ -19,19 +19,23 @@ 02111-1307, USA. */ -#import "SOGoTaskObject.h" +#import +#import +#import +#import #import #import #import #import #import -#import -#import -#import -#import "SOGoAptMailNotification.h" + +#import #import "NSArray+Appointments.h" +#import "SOGoAptMailNotification.h" + +#import "SOGoTaskObject.h" @interface SOGoTaskObject (PrivateAPI) diff --git a/SoObjects/Mailer/SOGoDraftObject.h b/SoObjects/Mailer/SOGoDraftObject.h index 1292c508..2995f722 100644 --- a/SoObjects/Mailer/SOGoDraftObject.h +++ b/SoObjects/Mailer/SOGoDraftObject.h @@ -48,34 +48,33 @@ /* contents */ -- (NSDictionary *)fetchInfo; -- (NSException *)storeInfo:(NSDictionary *)_info; +- (NSDictionary *) fetchInfo; +- (NSException *) storeInfo: (NSDictionary *) _info; /* attachments */ -- (NSArray *)fetchAttachmentNames; -- (BOOL)isValidAttachmentName:(NSString *)_name; -- (NSException *) saveAttachment: (NSData *)_attach +- (NSArray *) fetchAttachmentNames; +- (BOOL) isValidAttachmentName: (NSString *) _name; +- (NSException *) saveAttachment: (NSData *) _attach withMetadata: (NSDictionary *) metadata; -- (NSException *)deleteAttachmentWithName:(NSString *)_name; +- (NSException *) deleteAttachmentWithName: (NSString *) _name; /* NGMime representations */ -- (NGMimeMessage *)mimeMessage; +- (NGMimeMessage *) mimeMessage; -- (NSString *)saveMimeMessageToTemporaryFile; -- (NSString *)saveMimeMessageToTemporaryFileWithHeaders:(NSDictionary *)_addh; -- (NSException *)sendMimeMessageAtPath:(NSString *)_path; +- (NSString *) saveMimeMessageToTemporaryFile; +- (NSString *) saveMimeMessageToTemporaryFileWithHeaders:(NSDictionary *)_addh; -- (NSException *)sendMail; +- (NSException *) sendMail; /* operations */ -- (NSException *)delete; +- (NSException *) delete; /* fake being a SOGoMailObject */ -- (id)fetchParts:(NSArray *)_parts; +- (id) fetchParts: (NSArray *) _parts; @end diff --git a/SoObjects/Mailer/SOGoDraftObject.m b/SoObjects/Mailer/SOGoDraftObject.m index 999e1f32..1d627aba 100644 --- a/SoObjects/Mailer/SOGoDraftObject.m +++ b/SoObjects/Mailer/SOGoDraftObject.m @@ -41,7 +41,6 @@ #import #import #import -#import #import #import #import @@ -49,6 +48,7 @@ #import #import +#import #import "SOGoDraftObject.h" @@ -785,60 +785,8 @@ static BOOL showTextAttachmentsInline = NO; return ma; } -- (NSString *) _rawSender +- (NSException *) sendMail { - NSString *startEmail, *rawSender; - NSRange delimiter; - - startEmail = [self sender]; - delimiter = [startEmail rangeOfString: @"<"]; - if (delimiter.location == NSNotFound) - rawSender = startEmail; - else - { - rawSender = [startEmail substringFromIndex: NSMaxRange (delimiter)]; - delimiter = [rawSender rangeOfString: @">"]; - if (delimiter.location != NSNotFound) - rawSender = [rawSender substringToIndex: delimiter.location]; - } - - return rawSender; -} - -- (NSException *)sendMimeMessageAtPath:(NSString *)_path { - static NGSendMail *mailer = nil; - NSArray *recipients; - NSString *from; - - /* validate */ - - recipients = [self allRecipients]; - from = [self _rawSender]; - if ([recipients count] == 0) { - return [NSException exceptionWithHTTPStatus:500 /* server error */ - reason:@"draft has no recipients set!"]; - } - if ([from length] == 0) { - return [NSException exceptionWithHTTPStatus:500 /* server error */ - reason:@"draft has no sender (from) set!"]; - } - - /* setup mailer object */ - - if (mailer == nil) - mailer = [[NGSendMail sharedSendMail] retain]; - if (![mailer isSendMailAvailable]) { - [self errorWithFormat:@"missing sendmail binary!"]; - return [NSException exceptionWithHTTPStatus:500 /* server error */ - reason:@"did not find sendmail binary!"]; - } - - /* send mail */ - - return [mailer sendMailAtPath:_path toRecipients:recipients sender:from]; -} - -- (NSException *)sendMail { NSException *error; NSString *tmpPath; @@ -851,8 +799,10 @@ static BOOL showTextAttachmentsInline = NO; } /* send mail */ - error = [self sendMimeMessageAtPath:tmpPath]; - + error = [[SOGoMailer sharedMailer] sendMailAtPath: tmpPath + toRecipients: [self allRecipients] + sender: [self sender]]; + /* delete temporary file */ [self deleteTemporaryMessageFile:tmpPath]; diff --git a/SoObjects/Mailer/SOGoMailBaseObject.h b/SoObjects/Mailer/SOGoMailBaseObject.h index ad12a417..d2231786 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.h +++ b/SoObjects/Mailer/SOGoMailBaseObject.h @@ -59,6 +59,10 @@ - (NGImap4Connection *)imap4Connection; - (NGImap4ConnectionManager *)mailManager; + +- (NSString *) relativeImap4Name; +- (NSMutableString *) imap4URLString; + - (NSURL *)imap4URL; - (NSString *)imap4Login; - (NSString *)imap4Password; diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index 39f6dca1..0b3e7ef2 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -44,6 +44,7 @@ libSOGo_HEADER_FILES = \ NSCalendarDate+SOGo.h \ \ SOGoAuthenticator.h \ + SOGoMailer.h \ SOGoUser.h \ libSOGo_OBJC_FILES = \ @@ -71,6 +72,7 @@ libSOGo_OBJC_FILES = \ NSCalendarDate+SOGo.m \ \ SOGoAuthenticator.m \ + SOGoMailer.m \ SOGoUser.m \ # tools diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index 31c913ef..7cd8042b 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -43,6 +43,9 @@ - (NSString *) jsonRepresentation; +/* bare email addresses */ +- (NSString *) pureEMailAddress; + #ifndef GNUSTEP_BASE_LIBRARY - (BOOL) boolValue; #endif diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index 2f1d617c..38c09bad 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -249,6 +249,25 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil; return [NSString stringWithFormat: @"\"%@\"", representation]; } +- (NSString *) pureEMailAddress +{ + NSString *pureAddress; + NSRange delimiter; + + delimiter = [self rangeOfString: @"<"]; + if (delimiter.location == NSNotFound) + pureAddress = self; + else + { + pureAddress = [self substringFromIndex: NSMaxRange (delimiter)]; + delimiter = [pureAddress rangeOfString: @">"]; + if (delimiter.location != NSNotFound) + pureAddress = [pureAddress substringToIndex: delimiter.location]; + } + + return pureAddress; +} + #if LIB_FOUNDATION_LIBRARY - (BOOL) boolValue { diff --git a/SoObjects/SOGo/SOGoMailer.h b/SoObjects/SOGo/SOGoMailer.h new file mode 100644 index 00000000..29a4c6fc --- /dev/null +++ b/SoObjects/SOGo/SOGoMailer.h @@ -0,0 +1,50 @@ +/* SOGoMailer.h - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef SOGOMAILER_H +#define SOGOMAILER_H + +@class NSArray; +@class NSException; +@class NSString; + +@protocol NGMimePart; + +@interface SOGoMailer : NSObject +{ + NSString *mailingMechanism; + NSString *smtpServer; +} + ++ (id) sharedMailer; + +- (NSException *) sendMailAtPath: (NSString *) filename + toRecipients: (NSArray *) recipients + sender: (NSString *) sender; + +- (NSException *) sendMimePart: (id ) part + toRecipients: (NSArray *) recipients + sender: (NSString *) sender; + +@end + +#endif /* SOGOMAILER_H */ diff --git a/SoObjects/SOGo/SOGoMailer.m b/SoObjects/SOGo/SOGoMailer.m new file mode 100644 index 00000000..7ea6490b --- /dev/null +++ b/SoObjects/SOGo/SOGoMailer.m @@ -0,0 +1,256 @@ +/* SOGoMailer.m - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import + +#import "NSString+Utilities.h" +#import "SOGoMailer.h" + +#define defaultMailingMechanism @"sendmail" +#define defaultSMTPServer @"localhost" + +@implementation SOGoMailer + ++ (id) sharedMailer +{ + static id sharedMailer = nil; + + if (!sharedMailer) + sharedMailer = [self new]; + + return sharedMailer; +} + +- (id) init +{ + NSUserDefaults *ud; + + if ((self = [super init])) + { + ud = [NSUserDefaults standardUserDefaults]; + mailingMechanism = [ud stringForKey: @"SOGoMailingMechanism"]; + if (mailingMechanism) + { + if (!([mailingMechanism isEqualToString: @"sendmail"] + || [mailingMechanism isEqualToString: @"smtp"])) + { + [self logWithFormat: @"mechanism '%@' is invalid and" + @" should be set to 'sendmail' or 'smtp' instead", + mailingMechanism]; + [self logWithFormat: @"falling back to default '%@' mechanism", + defaultMailingMechanism]; + mailingMechanism = defaultMailingMechanism; + } + } + else + { + [self logWithFormat: @"default mailing mechanism set to '%@'", + defaultMailingMechanism]; + mailingMechanism = defaultMailingMechanism; + } + [mailingMechanism retain]; + + if ([mailingMechanism isEqualToString: @"smtp"]) + { + smtpServer = [ud stringForKey: @"SOGoSMTPServer"]; + if (!smtpServer) + { + [self logWithFormat: @"default smtp server set to '%@'", + defaultSMTPServer]; + smtpServer = defaultSMTPServer; + } + [smtpServer retain]; + } + else + smtpServer = nil; + } + + return self; +} + +- (void) dealloc +{ + [mailingMechanism release]; + [smtpServer release]; + [super dealloc]; +} + +- (NSException *) _sendmailSendData: (NSData *) mailData + toRecipients: (NSArray *) recipients + sender: (NSString *) sender +{ + NSException *result; + NGSendMail *mailer; + + mailer = [NGSendMail sharedSendMail]; + if ([mailer isSendMailAvailable]) + result = [mailer sendMailData: mailData + toRecipients: recipients + sender: sender]; + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message:" + @" no sendmail binary!"]; + + return result; +} + +- (NSException *) _sendMailData: (NSData *) mailData + withClient: (NGSmtpClient *) client + andRejections: (unsigned int) toErrors +{ + NSException *result; + + if (toErrors > 0) + [self logWithFormat: @"sending email despite address rejections"]; + if ([client sendData: mailData]) + result = nil; + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message:" + @" (smtp) failure when sending data"]; + + return result; +} + +- (NSException *) _smtpSendData: (NSData *) mailData + toRecipients: (NSArray *) recipients + sender: (NSString *) sender +{ + NGSmtpClient *client; + NSEnumerator *addresses; + NSString *currentTo; + unsigned int toErrors; + NSException *result; + + client = [NGSmtpClient smtpClient]; + if ([client connectToHost: smtpServer]) + { + if ([client hello] + && [client mailFrom: sender]) + { + toErrors = 0; + addresses = [recipients objectEnumerator]; + currentTo = [addresses nextObject]; + while (currentTo) + { + if (![client recipientTo: [currentTo pureEMailAddress]]) + { + [self logWithFormat: @"error with recipient '%@'", currentTo]; + toErrors++; + } + currentTo = [addresses nextObject]; + } + if (toErrors == [recipients count]) + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message:" + @" (smtp) all recipients discarded"]; + else + result = [self _sendMailData: mailData withClient: client + andRejections: toErrors]; + } + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message:" + @" (smtp) error when connecting"]; + [client quit]; + [client disconnect]; + } + + return result; +} + +- (NSException *) sendMailData: (NSData *) data + toRecipients: (NSArray *) recipients + sender: (NSString *) sender +{ + NSException *result; + + if (![recipients count]) + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message: no recipients set"]; + else + { + if (![sender length]) + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message: no sender set"]; + else + { + if ([mailingMechanism isEqualToString: @"sendmail"]) + result = [self _sendmailSendData: data + toRecipients: recipients + sender: [sender pureEMailAddress]]; + else + result = [self _smtpSendData: data + toRecipients: recipients + sender: [sender pureEMailAddress]]; + } + } + + return result; +} + +- (NSException *) sendMimePart: (id ) part + toRecipients: (NSArray *) recipients + sender: (NSString *) sender +{ + NSData *mailData; + + mailData = [[NGMimePartGenerator mimePartGenerator] + generateMimeFromPart: part]; + + return [self sendMailData: mailData + toRecipients: recipients + sender: sender]; +} + +- (NSException *) sendMailAtPath: (NSString *) filename + toRecipients: (NSArray *) recipients + sender: (NSString *) sender +{ + NSException *result; + NSData *mailData; + + mailData = [NSData dataWithContentsOfFile: filename]; + if ([mailData length] > 0) + result = [self sendMailData: mailData + toRecipients: recipients + sender: sender]; + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"cannot send message: no data" + @" (missing or empty file?)"]; + + return nil; +} + +@end diff --git a/UI/MailerUI/UIxMailAccountActions.m b/UI/MailerUI/UIxMailAccountActions.m index 56b9a0d8..6342e92f 100644 --- a/UI/MailerUI/UIxMailAccountActions.m +++ b/UI/MailerUI/UIxMailAccountActions.m @@ -103,6 +103,9 @@ folders = [self _jsonFolders: [rawFolders objectEnumerator]]; response = [context response]; + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=utf-8" + forKey: @"content-type"]; [response appendContentString: [folders jsonRepresentation]]; return response; diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index b0338a36..3111e172 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -268,7 +268,7 @@ folderURL = [folder imap4URL]; client = [[folder imap4Connection] client]; - infos = [client getQuotaRoot: [folder nameInContainer]]; + infos = [client getQuotaRoot: [folder relativeImap4Name]]; responseString = [[infos objectForKey: @"quotas"] jsonRepresentation]; [response appendContentString: responseString]; diff --git a/UI/SOGoUI/SOGoACLAdvisory.m b/UI/SOGoUI/SOGoACLAdvisory.m index 40cc8d0b..aefddbdd 100644 --- a/UI/SOGoUI/SOGoACLAdvisory.m +++ b/UI/SOGoUI/SOGoACLAdvisory.m @@ -23,10 +23,10 @@ #import #import #import -#import #import #import +#import #import #import #import @@ -195,9 +195,9 @@ [message setBody: body]; [body release]; - [[NGSendMail sharedSendMail] sendMimePart: message - toRecipients: [NSArray arrayWithObject: recipient] - sender: [activeUser primaryEmail]]; + [[SOGoMailer sharedMailer] sendMimePart: message + toRecipients: [NSArray arrayWithObject: recipient] + sender: [activeUser primaryEmail]]; } @end diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index c390268a..df32f1d7 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -1330,7 +1330,7 @@ function getMenus() { "-", "label-menu", "mark-menu", "-", null, onMenuViewMessageSource, - null, null, + null, onPrintCurrentMessage, onMenuDeleteMessage); menus["label-menu"] = new Array(null, "-", null , null, null, null , null, null); -- 2.39.5