Monotone-Parent: d730814de50b7c4fd0fa165b4b6e02e968ff60ef

Monotone-Revision: 148caf2ae66d2024b6008a2633e9145890921239

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2010-09-01T20:27:45
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2010-09-01 20:27:45 +00:00
parent 5ae619bea4
commit 4d5c0ff6f4
28 changed files with 770 additions and 33 deletions

View File

@ -1,3 +1,46 @@
2010-09-01 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/WebServerResources/MailerUI.js: (handleReturnReceipt): new
function, crafted to be executed both from the main window and the
popup mail window, where the value of the new "shouldAskReceipt"
field is evaluated and where a popup is displayed accordingly.
(onMessageConfirmMDN): new callback function for dialog mentionned
above.
* UI/WebServerResources/JavascriptAPIExtensions.js:
(String.prototype.cssIdToHungarianId) new helper method that
compose the hungarian representation from an identifier where the
parts are separated with a dash, such as css class and id
identifiers.
* UI/WebServerResources/UIxPreferences.js: added code for handling
prefs pertaining to return receipts.
* UI/MailerUI/UIxMailView.m (-shouldAskReceipt): new accessor that
returns a JS bool string when the current message satisfy the
conditions required for asking the user whether to send a receipt
or not. Additionally, it will send the receipt automatically if
the message category falls in a category where the unconditonnal
send is required as per the user preferences. If "ask" or "always"
is the returned value, the "$MDNSend" flag is automatically set on
the IMAP message, since we want to avoid asking the user twice.
* UI/PreferencesUI/UIxPreferences.m
(-_extractMainReceiptsPreferences:): new method for extracting
prefs pertaining to return receipts and save them in the user
prefs dictionary.
* SoObjects/SOGo/SOGoUserDefaults.m (-setAllowUserReceipt:)
(-allowUserReceipt, setUserReceiptNonRecipientAction:)
(userReceiptNonRecipientAction)
(setUserReceiptOutsideDomainAction:)
(userReceiptOutsideDomainAction, setUserReceiptAnyAction:)
(userReceiptAnyAction): new accessors pertaining to return
receipts.
* SoObjects/SOGo/SOGoUser.m (-_appendSystemMailAccount): append
preferences pertaining to return receipts.
2010-08-31 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/NSScanner+BSJSONAdditions.m (-scanJSONValue:):

View File

@ -502,13 +502,16 @@
- (void) _appendSystemMailAccount
{
NSString *fullName, *imapLogin, *imapServer, *signature, *encryption, *port, *scheme;
NSMutableDictionary *mailAccount, *identity, *mailboxes;
NSString *fullName, *imapLogin, *imapServer, *signature, *encryption, *port,
*scheme, *action;
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts;
NSMutableArray *identities;
NSArray *mails;
NSURL *url;
unsigned int count, max;
[self userDefaults];
mailAccount = [NSMutableDictionary new];
imapLogin = [[SOGoUserManager sharedUserManager]
@ -557,7 +560,7 @@
[mailAccount setObject: port forKey: @"port"];
[mailAccount setObject: encryption forKey: @"encryption"];
/* identities */
identities = [NSMutableArray new];
mails = [self allEmails];
[mailAccount setObject: [mails objectAtIndex: 0] forKey: @"name"];
@ -573,7 +576,7 @@
fullName = login;
[identity setObject: fullName forKey: @"fullName"];
[identity setObject: [mails objectAtIndex: count] forKey: @"email"];
signature = [[self userDefaults] mailSignature];
signature = [_defaults mailSignature];
if (signature)
[identity setObject: signature forKey: @"signature"];
[identities addObject: identity];
@ -585,9 +588,29 @@
[mailAccount setObject: identities forKey: @"identities"];
[identities release];
/* receipts */
if ([_defaults allowUserReceipt])
{
receipts = [NSMutableDictionary new];
[receipts setObject: @"allow" forKey: @"receiptAction"];
action = [_defaults userReceiptNonRecipientAction];
if (action)
[receipts setObject: action forKey: @"receiptNonRecipientAction"];
action = [_defaults userReceiptOutsideDomainAction];
if (action)
[receipts setObject: action forKey: @"receiptOutsideDomainAction"];
action = [_defaults userReceiptAnyAction];
if (action)
[receipts setObject: action forKey: @"receiptAnyAction"];
[mailAccount setObject: receipts forKey: @"receipts"];
[receipts release];
}
/* mailboxes */
mailboxes = [NSMutableDictionary new];
[self userDefaults];
[self _migrateFolderSettings];
[mailboxes setObject: [_defaults draftsFolderName]
forKey: @"Drafts"];

View File

@ -119,6 +119,15 @@ extern NSString *SOGoWeekStartFirstFullWeek;
- (void) setMailSignaturePlacement: (NSString *) newValue;
- (NSString *) mailSignaturePlacement;
- (void) setAllowUserReceipt: (BOOL) allow;
- (BOOL) allowUserReceipt;
- (void) setUserReceiptNonRecipientAction: (NSString *) action;
- (NSString *) userReceiptNonRecipientAction;
- (void) setUserReceiptOutsideDomainAction: (NSString *) action;
- (NSString *) userReceiptOutsideDomainAction;
- (void) setUserReceiptAnyAction: (NSString *) action;
- (NSString *) userReceiptAnyAction;
- (void) setMailUseOutlookStyleReplies: (BOOL) newValue;
- (BOOL) mailUseOutlookStyleReplies;

View File

@ -501,6 +501,46 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
return signaturePlacement;
}
- (void) setAllowUserReceipt: (BOOL) allow
{
[self setBool: allow forKey: @"SOGoMailReceiptAllow"];
}
- (BOOL) allowUserReceipt
{
return [self boolForKey: @"SOGoMailReceiptAllow"];
}
- (void) setUserReceiptNonRecipientAction: (NSString *) action
{
[self setObject: action forKey: @"SOGoMailReceiptNonRecipientAction"];
}
- (NSString *) userReceiptNonRecipientAction
{
return [self stringForKey: @"SOGoMailReceiptNonRecipientAction"];
}
- (void) setUserReceiptOutsideDomainAction: (NSString *) action
{
[self setObject: action forKey: @"SOGoMailReceiptOutsideDomainAction"];
}
- (NSString *) userReceiptOutsideDomainAction
{
return [self stringForKey: @"SOGoMailReceiptOutsideDomainAction"];
}
- (void) setUserReceiptAnyAction: (NSString *) action
{
[self setObject: action forKey: @"SOGoMailReceiptAnyAction"];
}
- (NSString *) userReceiptAnyAction
{
return [self stringForKey: @"SOGoMailReceiptAnyAction"];
}
- (void) setMailUseOutlookStyleReplies: (BOOL) newValue
{
[self setBool: newValue forKey: @"SOGoMailUseOutlookStyleReplies"];

View File

@ -110,6 +110,8 @@
"Load Images" = "Carregar Imagens";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Prioridade";
"highest" = "Muito Alta";

View File

@ -110,6 +110,8 @@
"Load Images" = "Nahrát obrázky";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Priorita";
"highest" = "Nejvyšší";

View File

@ -110,6 +110,8 @@
"Load Images" = "Afbeeldingen laden";
"Return Receipt" = "Ontvangstbevestiging";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Prioriteit";
"highest" = "Hoogste";

View File

@ -110,6 +110,8 @@
"Load Images" = "Load Images";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Priority";
"highest" = "Highest";

View File

@ -110,6 +110,8 @@
"Load Images" = "Télécharger les images";
"Return Receipt" = "Accusé de réception";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "L'auteur de ce message a souhaité être prévenu lorsque vous lirez ce message. Souhaitez-vous avertir l'expéditeur ?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "Ceci est un accusé de réception pour le courrier électronique envoyé à %@.\n\nNote : Cet accusé de réception indique seulement que le message a été affiché sur l'ordinateur du destinataire. Il n'y a aucune garantie que le destinataire ait lu ou compris le contenu du message.";
"Priority" = "Priorité";
"highest" = "Maximale";

View File

@ -110,6 +110,8 @@
"Load Images" = "Bilder laden";
"Return Receipt" = "Empfangsbestätigung";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Priorität";
"highest" = "Sehr hoch";

View File

@ -110,6 +110,8 @@
"Load Images" = "Képek betöltése";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Sürgősség";
"highest" = "nagyon sürgős";

View File

@ -110,6 +110,8 @@
"Load Images" = "Carica Immagini";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Priorità";
"highest" = "Molto alta";

View File

@ -110,6 +110,8 @@
"Load Images" = "Załaduj obrazki";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Priorytet";
"highest" = "Najwyższy";

View File

@ -110,6 +110,8 @@
"Load Images" = "Загрузить изображения";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Важность";
"highest" = "Самый высокий";

View File

@ -110,6 +110,8 @@
"Load Images" = "Load Images";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Priority";
"highest" = "Highest";

View File

@ -110,6 +110,8 @@
"Load Images" = "Ladda bilder";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Prioritet";
"highest" = "Högst";

View File

@ -24,14 +24,27 @@
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSException+misc.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSString+misc.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeMultipartBody.h>
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <SoObjects/Mailer/SOGoMailObject.h>
#import <SoObjects/Mailer/SOGoMailAccount.h>
#import <SoObjects/Mailer/SOGoMailFolder.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoMailer.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailFolder.h>
#import <SOGoUI/UIxComponent.h>
#import <MailPartViewers/UIxMailRenderingContext.h> // cyclic
@ -40,6 +53,8 @@
@interface UIxMailView : UIxComponent
{
id currentAddress;
NSString *shouldAskReceipt;
NSString *matchingIdentityEMail;
}
@end
@ -54,7 +69,13 @@ static NSString *mailETag = nil;
UIX_MAILER_MAJOR_VERSION,
UIX_MAILER_MINOR_VERSION,
UIX_MAILER_SUBMINOR_VERSION];
NSLog(@"Note: using constant etag for mail viewer: '%@'", mailETag);
NSLog (@"Note: using constant etag for mail viewer: '%@'", mailETag);
}
- (void) dealloc
{
[matchingIdentityEMail release];
[super dealloc];
}
/* accessors */
@ -167,15 +188,391 @@ static NSString *mailETag = nil;
if (![self message]) // TODO: redirect to proper error
return [NSException exceptionWithHTTPStatus:404 /* Not Found */
reason:@"did not find specified message!"];
return self;
}
- (BOOL) isInlineViewer
/* MDN */
- (BOOL) _userHasEMail: (NSString *) email
{
return NO;
NSArray *identities;
NSString *identityEmail;
SOGoMailAccount *account;
int count, max;
BOOL rc;
account = [[self clientObject] mailAccountFolder];
identities = [account identities];
max = [identities count];
for (count = 0; !rc && count < max; count++)
{
identityEmail = [[identities objectAtIndex: count]
objectForKey: @"email"];
rc = [identityEmail isEqualToString: email];
}
return rc;
}
- (BOOL) _messageHasDraftOrMDNSentFlag
{
NSArray *flags;
NSDictionary *coreInfos;
coreInfos = [[self clientObject] fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
return ([flags containsObject: @"draft"]
|| [flags containsObject: @"$mdnsent"]);
}
- (NSString *) _matchingIdentityEMail
{
NSMutableArray *recipients;
NSArray *headerRecipients;
NSString *currentEMail;
NGImap4EnvelopeAddress *address;
NSInteger count, max;
SOGoMailObject *co;
if (!matchingIdentityEMail)
{
recipients = [NSMutableArray array];
co = [self clientObject];
headerRecipients = [co toEnvelopeAddresses];
if ([headerRecipients count])
[recipients addObjectsFromArray: headerRecipients];
headerRecipients = [co ccEnvelopeAddresses];
if ([headerRecipients count])
[recipients addObjectsFromArray: headerRecipients];
max = [recipients count];
for (count = 0; !matchingIdentityEMail && count < max; count++)
{
address = [recipients objectAtIndex: count];
currentEMail = [NSString stringWithFormat: @"%@@%@",
[address mailbox],
[address host]];
if ([self _userHasEMail: currentEMail])
{
matchingIdentityEMail = currentEMail;
[matchingIdentityEMail retain];
}
}
}
return matchingIdentityEMail;
}
- (NSString *) _domainFromEMail: (NSString *) email
{
NSString *domain;
NSRange separator;
separator = [email rangeOfString: @"@"];
if (separator.location != NSNotFound)
domain = [email substringFromIndex: NSMaxRange (separator)];
else
domain = nil;
return domain;
}
- (NSArray *) _userEMailDomains
{
NSMutableArray *domains;
NSArray *identities;
NSString *email, *domain;
SOGoMailAccount *account;
NSInteger count, max;
account = [[self clientObject] mailAccountFolder];
identities = [account identities];
max = [identities count];
domains = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
email = [[identities objectAtIndex: count]
objectForKey: @"email"];
domain = [self _domainFromEMail: email];
if (domain)
[domains addObject: domain];
}
return domains;
}
- (BOOL) _senderIsInUserDomain: (NSDictionary *) headers
{
NSString *sender, *senderDomain;
BOOL rc;
sender = [[headers objectForKey: @"from"] pureEMailAddress];
senderDomain = [self _domainFromEMail: sender];
if (senderDomain)
rc = [[self _userEMailDomains] containsObject: senderDomain];
else
rc = NO;
return rc;
}
- (NSString *) _receiptAction
{
SOGoUserDefaults *ud;
NSString *action;
NSDictionary *headers;
headers = [[self clientObject] mailHeaders];
ud = [[context activeUser] userDefaults];
if ([ud allowUserReceipt])
{
if ([self _matchingIdentityEMail])
{
if ([self _senderIsInUserDomain: headers])
action = [ud userReceiptAnyAction];
else
action = [ud userReceiptOutsideDomainAction];
}
else
action = [ud userReceiptNonRecipientAction];
}
else
action = @"ignore";
return action;
}
- (void) _flagMessageWithMDNSent
{
[[self clientObject] addFlags: @"$MDNSent"];
}
- (void) _appendReceiptTextToBody: (NGMimeMultipartBody *) body
{
NGMutableHashMap *map;
NGMimeBodyPart *bodyPart;
NSString *textPartFormat, *textPartMessage;
map = [[NGMutableHashMap alloc] initWithCapacity: 1];
[map setObject: @"text/plain; charset=utf-8; format=flowed"
forKey: @"content-type"];
bodyPart = [[NGMimeBodyPart alloc] initWithHeader: map];
[map release];
textPartFormat = [self labelForKey: @"This is a Return Receipt for the mail"
@" that you sent to %@.\n\nNote: This Return Receipt"
@" only acknowledges that the message was displayed"
@" on the recipient's computer. There is no"
@" guarantee that the recipient has read or"
@" understood the message contents."];
textPartMessage = [NSString stringWithFormat: textPartFormat,
[self _matchingIdentityEMail]];
[bodyPart setBody: [textPartMessage
dataUsingEncoding: NSUTF8StringEncoding]];
[body addBodyPart: bodyPart];
[bodyPart release];
}
- (void) _appendMDNToBody: (NGMimeMultipartBody *) body
{
NGMutableHashMap *map;
NGMimeBodyPart *bodyPart;
NSString *messageId;
NSMutableString *mdnPartMessage;
map = [[NGMutableHashMap alloc] initWithCapacity: 3];
[map addObject: @"message/disposition-notification; name=\"MDNPart2.txt\""
forKey: @"content-type"];
[map addObject: @"inline" forKey: @"content-disposition"];
[map addObject: @"7bit" forKey: @"content-transfer-encoding"];
bodyPart = [[NGMimeBodyPart alloc] initWithHeader: map];
[map release];
mdnPartMessage = [[NSMutableString alloc] initWithCapacity: 100];
[mdnPartMessage appendFormat: @"Reporting-UA: SOGoMail %d.%d.%d\n",
UIX_MAILER_MAJOR_VERSION,
UIX_MAILER_MINOR_VERSION,
UIX_MAILER_SUBMINOR_VERSION];
[mdnPartMessage appendFormat: @"Final-Recipient: rfc822;%@\n",
[self _matchingIdentityEMail]];
messageId = [[self clientObject] messageId];
[mdnPartMessage appendFormat: @"Original-Message-ID: %@\n",
messageId];
[mdnPartMessage appendString: @"Disposition:"
@" manual-action/MDN-sent-manually; displayed"];
[bodyPart setBody: [mdnPartMessage
dataUsingEncoding: NSASCIIStringEncoding]];
[mdnPartMessage release];
[body addBodyPart: bodyPart];
[bodyPart release];
}
- (void) _appendHeadersToBody: (NGMimeMultipartBody *) body
{
NGMutableHashMap *map;
NGMimeBodyPart *bodyPart;
NSDictionary *coreInfos;
map = [[NGMutableHashMap alloc] initWithCapacity: 3];
[map addObject: @"text/rfc822-headers; name=\"MDNPart3.txt\""
forKey: @"content-type"];
[map addObject: @"inline" forKey: @"content-disposition"];
[map addObject: @"7bit" forKey: @"content-transfer-encoding"];
bodyPart = [[NGMimeBodyPart alloc] initWithHeader: map];
[map release];
coreInfos = [[self clientObject] fetchCoreInfos];
[bodyPart setBody: [coreInfos objectForKey: @"header"]];
[body addBodyPart: bodyPart];
[bodyPart release];
}
- (NGHashMap *) _receiptMessageHeaderTo: (NSString *) email
{
NGMutableHashMap *map;
NSString *subject;
map = [[NGMutableHashMap alloc] initWithCapacity: 1];
[map autorelease];
[map setObject: email forKey: @"to"];
[map setObject: [self _matchingIdentityEMail] forKey: @"from"];
[map setObject: @"multipart/report; report-type=disposition-notification"
forKey: @"content-type"];
subject = [NSString stringWithFormat:
[self labelForKey: @"Return Receipt (displayed) - %@"],
[self messageSubject]];
[map setObject: subject forKey: @"subject"];
return map;
}
- (void) _sendEMailReceiptTo: (NSString *) email
{
NGMimeMultipartBody *body;
NGMimeMessage *message;
NGMimeMessageGenerator *generator;
SOGoDomainDefaults *dd;
message = [NGMimeMessage
messageWithHeader: [self _receiptMessageHeaderTo: email]];
body = [[NGMimeMultipartBody alloc] initWithPart: message];
[self _appendReceiptTextToBody: body];
[self _appendMDNToBody: body];
[self _appendHeadersToBody: body];
[message setBody: body];
[body release];
dd = [[context activeUser] domainDefaults];
generator = [NGMimeMessageGenerator new];
[generator autorelease];
if (![[SOGoMailer mailerWithDomainDefaults: dd]
sendMailData: [generator generateMimeFromPart: message]
toRecipients: [NSArray arrayWithObject: email]
sender: [self _matchingIdentityEMail]])
[self _flagMessageWithMDNSent];
}
- (NSString *) shouldAskReceipt
{
NSDictionary *mailHeaders;
NSString *email, *action;
if (!shouldAskReceipt)
{
shouldAskReceipt = @"false";
mailHeaders = [[self clientObject] mailHeaders];
email = [mailHeaders objectForKey: @"disposition-notification-to"];
if (!email)
{
email = [mailHeaders objectForKey: @"x-confirm-reading-to"];
if (!email)
email = [mailHeaders objectForKey: @"return-receipt-to"];
}
if (email)
{
if (![self _userHasEMail: email]
&& ![self _messageHasDraftOrMDNSentFlag])
{
action = [self _receiptAction];
if ([action isEqualToString: @"ask"])
{
shouldAskReceipt = @"true";
[self _flagMessageWithMDNSent];
}
else if ([action isEqualToString: @"send"])
[self _sendEMailReceiptTo: email];
}
}
}
return shouldAskReceipt;
}
- (WOResponse *) sendMDNAction
{
WOResponse *response;
NSDictionary *mailHeaders;
NSString *email, *action;
mailHeaders = [[self clientObject] mailHeaders];
email = [mailHeaders objectForKey: @"disposition-notification-to"];
if (!email)
{
email = [mailHeaders objectForKey: @"x-confirm-reading-to"];
if (!email)
email = [mailHeaders objectForKey: @"return-receipt-to"];
}
/* We perform most of the validation steps that were done in
-shouldAskReceipt in order to enforce consistency. */
if (email)
{
if ([self _userHasEMail: email])
response = [self responseWithStatus: 403
andString: (@"One cannot send an MDN to"
@" oneself.")];
else
{
if ([self _messageHasDraftOrMDNSentFlag])
response = [self responseWithStatus: 403
andString: (@"The original message is"
@" flagged as a draft or an"
@" MDN has already been sent"
@" for it.")];
else
{
action = [self _receiptAction];
if ([action isEqualToString: @"ask"])
{
[self _sendEMailReceiptTo: email];
response = [self responseWithStatus: 204];
}
else
response = [self responseWithStatus: 403
andString: (@"No notification header found in"
@" original message.")];
}
}
}
else
response = [self responseWithStatus: 403
andString: (@"No notification header found in"
@" original message.")];
return response;
}
/* /MDN */
- (BOOL) mailIsDraft
{
return [[self clientObject] isInDraftsFolder];

View File

@ -110,6 +110,8 @@
"Load Images" = "Завантажити зображення";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Важливість";
"highest" = "Найвища";

View File

@ -110,6 +110,8 @@
"Load Images" = "Llwytho Delweddau";
"Return Receipt" = "Return Receipt";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
"Priority" = "Blaenoriaeth";
"highest" = "Uchaf";

View File

@ -213,6 +213,11 @@
protectedBy = "View";
pageName = "UIxMailView";
};
sendMDN = {
protectedBy = "View";
pageName = "UIxMailView";
actionName = "sendMDN";
};
viewsource = {
protectedBy = "View";
actionClass = "UIxMailSourceView";

View File

@ -1096,6 +1096,45 @@
}
}
- (BOOL) _validateReceiptAction: (NSString *) action
{
return ([action isKindOfClass: [NSString class]]
&& ([action isEqualToString: @"ignore"]
|| [action isEqualToString: @"send"]
|| [action isEqualToString: @"ask"]));
}
- (void) _extractMainReceiptsPreferences: (NSDictionary *) account
{
/* We perform some validation here as we have no guaranty on the input
validity. */
NSDictionary *receipts;
NSString *action;
if ([account isKindOfClass: [NSDictionary class]])
{
receipts = [account objectForKey: @"receipts"];
if ([receipts isKindOfClass: [NSDictionary class]])
{
action = [receipts objectForKey: @"receiptAction"];
[userDefaults
setAllowUserReceipt: [action isEqualToString: @"allow"]];
action = [receipts objectForKey: @"receiptNonRecipientAction"];
if ([self _validateReceiptAction: action])
[userDefaults setUserReceiptNonRecipientAction: action];
action = [receipts objectForKey: @"receiptOutsideDomainAction"];
if ([self _validateReceiptAction: action])
[userDefaults setUserReceiptOutsideDomainAction: action];
action = [receipts objectForKey: @"receiptAnyAction"];
if ([self _validateReceiptAction: action])
[userDefaults setUserReceiptAnyAction: action];
}
}
}
- (BOOL) _validateAccountIdentities: (NSArray *) identities
{
static NSString *identityKeys[] = { @"fullName", @"email", nil };
@ -1160,9 +1199,11 @@
if (!knownKeys)
{
knownKeys = [NSArray arrayWithObjects: @"name", @"serverName",
knownKeys = [NSArray arrayWithObjects: @"name", @"serverName", @"port",
@"userName", @"password", @"encryption",
@"identities", @"mailboxes", @"port", nil];
@"identities", @"mailboxes",
@"receipts",
nil];
[knownKeys retain];
}
@ -1254,6 +1295,7 @@
if (max > 0)
{
[self _extractMainSignature: [accounts objectAtIndex: 0]];
[self _extractMainReceiptsPreferences: [accounts objectAtIndex: 0]];
if ([self mailAuxiliaryUserAccountsEnabled])
[self _extractAuxiliaryAccounts: accounts];

View File

@ -5,6 +5,7 @@
xmlns:uix="OGo:uix"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<input type="hidden" const:id="shouldAskReceipt" var:value="shouldAskReceipt"/>
<var:if var:condition="mailIsDraft"
><input const:name="editDraftButton" const:id="editDraftButton"
type="button" class="button" label:value="Edit Draft..."
@ -33,10 +34,6 @@
<td class="mailer_fieldvalue">
<var:string value="clientObject.date"
formatter="context.mailDateFormatter"/>
<!-- TODO:
(<a rsrc:href="tbird_073_viewer.png">screenshot</a>)
-->
</td>
</tr>

View File

@ -225,31 +225,71 @@
<label><var:string label:value="Server Name:"/>
<input const:name="serverName" const:id="serverName" type="text" const:value=""/></label>
<label><var:string label:value="Port:"/>
<input const:name="port" const:id="port" type="text" const:value=""/></label><br/><br/>
<label><var:string label:value="User Name:"/>
<input const:name="userName" const:id="userName" type="text" const:value=""/></label><br/>
<label><var:string label:value="Password:"/>
<input const:name="password" const:id="password" type="password" const:value=""/></label>
<input const:name="encryption" type="hidden" const:value="none"/>
<hr/>
<input const:name="port" const:id="port" type="text" const:value=""/></label><br/>
<var:string label:value="Encryption:"/>
<label><input const:name="encryption" type="radio" const:value="none"/>
<var:string label:value="None"/></label>
<label><input const:name="encryption" type="radio" const:value="ssl"/>
<var:string label:value="SSL"/></label>
<label><input const:name="encryption" type="radio" const:value="tls"/>
<var:string label:value="TLS"/></label>
<var:string label:value="TLS"/></label><br/>
<label><var:string label:value="User Name:"/>
<input const:name="userName" const:id="userName" type="text" const:value=""/></label><br/>
<label><var:string label:value="Password:"/>
<input const:name="password" const:id="password" type="password" const:value=""/></label>
<input const:name="encryption" type="hidden" const:value="none"/>
</fieldset>
<fieldset const:id="identityInfo">
<label><var:string label:value="Full Name:"/>
<input const:name="fullName" const:id="fullName" type="text" const:value=""
/></label><br/>
<label><var:string label:value="Email:"/>
<input const:name="email" const:id="email" type="text" const:value=""/></label><br/><br/>
<input const:name="email" const:id="email" type="text" const:value=""/></label><br/>
<var:string label:value="Signature:"/>
<span id="actSignature"><!--space --></span>
</fieldset>
<fieldset const:id="returnReceiptsInfo">
<var:string
label:value="When I receive a request for a return receipt:"
/><br/>
<label><input const:name="receipt-action" const:id="receipt-action-ignore"
type="radio" const:value="ignore"/>
<var:string
label:value="Never send a return receipt"/></label
><br/>
<label><input const:name="receipt-action" const:id="receipt-action-allow"
type="radio" const:value="allow"/>
<var:string
label:value="Allow return receipts for some messages"/></label
><br/>
<div id="receiptOptions">
<var:string
label:value="If I'm not in the To or Cc of the message:"/>
<select name="receipt-non-recipient-action" id="receipt-non-recipient-action">
<option const:value="ignore"><var:string label:value="Never send"/></option>
<option const:value="send"><var:string label:value="Always send"/></option>
<option const:value="ask"><var:string label:value="Ask me"/></option>
</select><br/>
<var:string
label:value="If the sender is outside my domain:"/>
<select name="receipt-outside-domain-action" id="receipt-outside-domain-action">
<option const:value="ignore"><var:string label:value="Never send"/></option>
<option const:value="send"><var:string label:value="Always send"/></option>
<option const:value="ask"><var:string label:value="Ask me"/></option>
</select><br/>
<var:string
label:value="In all other cases:"/>
<select name="receipt-any-action" id="receipt-any-action">
<option const:value="ignore"><var:string label:value="Never send"/></option>
<option const:value="send"><var:string label:value="Always send"/></option>
<option const:value="ask"><var:string label:value="Ask me"/></option>
</select><br/>
</div>
</fieldset>
</div>
</div>

View File

@ -31,6 +31,16 @@ String.prototype.capitalize = function() {
});
};
String.prototype.cssIdToHungarianId = function() {
var parts = this.split("-");
var newId = parts[0];
for (var i = 1; i < parts.length; i++) {
newId += parts[i].capitalize();
}
return newId;
}
String.prototype.decodeEntities = function() {
return this.replace(/&#(\d+);/g,
function(wholematch, parenmatch1) {

View File

@ -1425,6 +1425,35 @@ function onAttachmentClick (event) {
return false;
}
function handleReturnReceipt() {
var input = $("shouldAskReceipt");
if (input) {
if (eval(input.value)) {
showConfirmDialog(_("Return Receipt"),
_("The sender of this message has asked to be notified when you read this message. "
+ "Do you with to notify the sender?"),
onReadMessageConfirmMDN);
}
}
}
function onReadMessageConfirmMDN(event) {
var messageURL;
if (window.opener && window.opener.Mailer) {
/* from UIxMailPopupView */
messageURL = (ApplicationBaseURL + encodeURI(mailboxName)
+ "/" + messageName);
}
else {
/* from main window */
messageURL = (ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/"
+ Mailer.currentMessages[Mailer.currentMailbox]);
}
disposeDialog();
var url = messageURL + "/sendMDN";
triggerAjaxRequest(url);
}
function loadMessageCallback(http) {
var div = $('messageContent');
@ -1435,7 +1464,7 @@ function loadMessageCallback(http) {
resizeMailContent();
configureLoadImagesButton();
configureSignatureFlagImage();
handleReturnReceipt();
if (http.callbackData) {
var cachedMessage = new Array();
var msguid = http.callbackData.msguid;

View File

@ -14,6 +14,8 @@ function initPopupMailer(event) {
configureSignatureFlagImage();
window.messageUID = mailboxName + "/" + messageName;
handleReturnReceipt();
}
function onICalendarButtonClick(event) {

View File

@ -190,3 +190,6 @@ P.infoMessage#passwordError
height: 90px;
margin: 0px auto;
margin-bottom: 10px; }
#receiptOptions
{ text-align: right; }

View File

@ -414,6 +414,16 @@ function initMailAccounts() {
}
$("actSignature").observe("click", onMailIdentitySignatureClick);
displayMailAccount(mailAccounts[0], true);
info = $("returnReceiptsInfo");
inputs = info.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
$(inputs[i]).observe("change", onMailReceiptInfoChange);
}
inputs = info.getElementsByTagName("select");
for (var i = 0; i < inputs.length; i++) {
$(inputs[i]).observe("change", onMailReceiptActionChange);
}
}
function onMailAccountInfoChange(event) {
@ -432,6 +442,31 @@ function onMailIdentityInfoChange(event) {
hasChanged.value = "1";
}
function onMailReceiptInfoChange(event) {
if (!this.mailAccount["receipts"]) {
this.mailAccount["receipts"] = {};
}
var keyName = this.name.cssIdToHungarianId();
this.mailAccount["receipts"][keyName] = this.value;
var popupIds = [ "receipt-non-recipient-action",
"receipt-outside-domain-action",
"receipt-any-action" ];
var receiptActionsDisable = (this.value == "ignore");
for (var i = 0; i < popupIds.length; i++) {
var actionPopup = $(popupIds[i]);
actionPopup.disabled = receiptActionsDisable;
}
}
function onMailReceiptActionChange(event) {
if (!this.mailAccount["receipts"]) {
this.mailAccount["receipts"] = {};
}
var keyName = this.name.cssIdToHungarianId();
this.mailAccount["receipts"][keyName] = this.value;
}
function onMailIdentitySignatureClick(event) {
if (!this.readOnly) {
var dialogId = "signatureDialog";
@ -526,20 +561,26 @@ function onMailAccountEntryClick(event) {
}
function displayMailAccount(mailAccount, readOnly) {
var editor = $("mailAccountEditor");
var inputs = editor.getElementsByTagName("input");
var fieldSet = $("accountInfo");
var inputs = fieldSet.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
inputs[i].disabled = readOnly;
inputs[i].mailAccount = mailAccount;
}
fieldSet = $("identityInfo");
inputs = fieldSet.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
inputs[i].disabled = readOnly;
inputs[i].mailAccount = mailAccount;
}
var encryption = "none";
var form = $("mainForm");
var encryption = "none";
var encRadioValues = [ "none", "ssl", "tls" ];
if (mailAccount["encryption"]) {
encryption = mailAccount["encryption"];
}
var form = $("mainForm");
form.setRadioValue("encryption", encRadioValues.indexOf(encryption));
var port;
@ -567,6 +608,34 @@ function displayMailAccount(mailAccount, readOnly) {
$("email").value = identity["email"] || "";
displayAccountSignature(mailAccount);
var receiptAction = "ignore";
var receiptActionValues = [ "ignore", "allow" ];
if (mailAccount["receipts"] && mailAccount["receipts"]["receiptAction"]) {
receiptAction = mailAccount["receipts"]["receiptAction"];
}
for (var i = 0; i < receiptActionValues.length; i++) {
var keyName = "receipt-action-" + receiptActionValues[i];
var input = $(keyName);
input.mailAccount = mailAccount;
}
form.setRadioValue("receipt-action",
receiptActionValues.indexOf(receiptAction));
var popupIds = [ "receipt-non-recipient-action",
"receipt-outside-domain-action",
"receipt-any-action" ];
var receiptActionsDisable = (receiptAction == "ignore");
for (var i = 0; i < popupIds.length; i++) {
var actionPopup = $(popupIds[i]);
actionPopup.disabled = receiptActionsDisable;
var settingValue = "ignore";
var settingName = popupIds[i].cssIdToHungarianId();
if (mailAccount["receipts"] && mailAccount["receipts"][settingName]) {
settingValue = mailAccount["receipts"][settingName];
}
actionPopup.value = settingValue;
actionPopup.mailAccount = mailAccount;
}
}
function displayAccountSignature(mailAccount) {