From 4d5c0ff6f4ae96a5df59b93ee8ff420ed41903fc Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 1 Sep 2010 20:27:45 +0000 Subject: [PATCH] Monotone-Parent: d730814de50b7c4fd0fa165b4b6e02e968ff60ef Monotone-Revision: 148caf2ae66d2024b6008a2633e9145890921239 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-09-01T20:27:45 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 43 ++ SoObjects/SOGo/SOGoUser.m | 33 +- SoObjects/SOGo/SOGoUserDefaults.h | 9 + SoObjects/SOGo/SOGoUserDefaults.m | 40 ++ .../Localizable.strings | 2 + UI/MailerUI/Czech.lproj/Localizable.strings | 2 + UI/MailerUI/Dutch.lproj/Localizable.strings | 2 + UI/MailerUI/English.lproj/Localizable.strings | 2 + UI/MailerUI/French.lproj/Localizable.strings | 2 + UI/MailerUI/German.lproj/Localizable.strings | 2 + .../Hungarian.lproj/Localizable.strings | 2 + UI/MailerUI/Italian.lproj/Localizable.strings | 2 + UI/MailerUI/Polish.lproj/Localizable.strings | 2 + UI/MailerUI/Russian.lproj/Localizable.strings | 2 + UI/MailerUI/Spanish.lproj/Localizable.strings | 2 + UI/MailerUI/Swedish.lproj/Localizable.strings | 2 + UI/MailerUI/UIxMailView.m | 411 +++++++++++++++++- .../Ukrainian.lproj/Localizable.strings | 2 + UI/MailerUI/Welsh.lproj/Localizable.strings | 2 + UI/MailerUI/product.plist | 5 + UI/PreferencesUI/UIxPreferences.m | 46 +- UI/Templates/MailerUI/UIxMailView.wox | 5 +- UI/Templates/PreferencesUI/UIxPreferences.wox | 60 ++- .../JavascriptAPIExtensions.js | 10 + UI/WebServerResources/MailerUI.js | 31 +- UI/WebServerResources/UIxMailPopupView.js | 2 + UI/WebServerResources/UIxPreferences.css | 3 + UI/WebServerResources/UIxPreferences.js | 77 +++- 28 files changed, 770 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index acc094e2e..c6334f103 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2010-09-01 Wolfgang Sourdeau + + * 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 * SoObjects/SOGo/NSScanner+BSJSONAdditions.m (-scanJSONValue:): diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index 2e7469082..1485ab28e 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -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"]; diff --git a/SoObjects/SOGo/SOGoUserDefaults.h b/SoObjects/SOGo/SOGoUserDefaults.h index f4940fa35..95845e686 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.h +++ b/SoObjects/SOGo/SOGoUserDefaults.h @@ -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; diff --git a/SoObjects/SOGo/SOGoUserDefaults.m b/SoObjects/SOGo/SOGoUserDefaults.m index 8513efa4f..7bab51af8 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.m +++ b/SoObjects/SOGo/SOGoUserDefaults.m @@ -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"]; diff --git a/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings b/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings index c798d8eed..48d02ed4f 100644 --- a/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings +++ b/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/Czech.lproj/Localizable.strings b/UI/MailerUI/Czech.lproj/Localizable.strings index be933a78b..e07409051 100644 --- a/UI/MailerUI/Czech.lproj/Localizable.strings +++ b/UI/MailerUI/Czech.lproj/Localizable.strings @@ -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šší"; diff --git a/UI/MailerUI/Dutch.lproj/Localizable.strings b/UI/MailerUI/Dutch.lproj/Localizable.strings index 067336106..29c5c5f99 100644 --- a/UI/MailerUI/Dutch.lproj/Localizable.strings +++ b/UI/MailerUI/Dutch.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/English.lproj/Localizable.strings b/UI/MailerUI/English.lproj/Localizable.strings index 19e1fba1a..1cd3444ec 100644 --- a/UI/MailerUI/English.lproj/Localizable.strings +++ b/UI/MailerUI/English.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/French.lproj/Localizable.strings b/UI/MailerUI/French.lproj/Localizable.strings index 4bfaa91e8..de1d1e05f 100644 --- a/UI/MailerUI/French.lproj/Localizable.strings +++ b/UI/MailerUI/French.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/German.lproj/Localizable.strings b/UI/MailerUI/German.lproj/Localizable.strings index f6426d63e..dc7fdd39a 100644 --- a/UI/MailerUI/German.lproj/Localizable.strings +++ b/UI/MailerUI/German.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/Hungarian.lproj/Localizable.strings b/UI/MailerUI/Hungarian.lproj/Localizable.strings index f4ef0db5a..7917a9518 100644 --- a/UI/MailerUI/Hungarian.lproj/Localizable.strings +++ b/UI/MailerUI/Hungarian.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/Italian.lproj/Localizable.strings b/UI/MailerUI/Italian.lproj/Localizable.strings index 5d0437224..91ba961c1 100644 --- a/UI/MailerUI/Italian.lproj/Localizable.strings +++ b/UI/MailerUI/Italian.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/Polish.lproj/Localizable.strings b/UI/MailerUI/Polish.lproj/Localizable.strings index 2019e5334..3089c28c1 100644 --- a/UI/MailerUI/Polish.lproj/Localizable.strings +++ b/UI/MailerUI/Polish.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/Russian.lproj/Localizable.strings b/UI/MailerUI/Russian.lproj/Localizable.strings index 11bb418f0..6af3ea01c 100644 --- a/UI/MailerUI/Russian.lproj/Localizable.strings +++ b/UI/MailerUI/Russian.lproj/Localizable.strings @@ -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" = "Самый высокий"; diff --git a/UI/MailerUI/Spanish.lproj/Localizable.strings b/UI/MailerUI/Spanish.lproj/Localizable.strings index dfbcfc901..b966070df 100644 --- a/UI/MailerUI/Spanish.lproj/Localizable.strings +++ b/UI/MailerUI/Spanish.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/Swedish.lproj/Localizable.strings b/UI/MailerUI/Swedish.lproj/Localizable.strings index d337d07d2..b519ae9e2 100644 --- a/UI/MailerUI/Swedish.lproj/Localizable.strings +++ b/UI/MailerUI/Swedish.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/UIxMailView.m b/UI/MailerUI/UIxMailView.m index 604408348..6ce928ee4 100644 --- a/UI/MailerUI/UIxMailView.m +++ b/UI/MailerUI/UIxMailView.m @@ -24,14 +24,27 @@ #import #import #import +#import #import + +#import +#import +#import +#import + #import #import #import #import -#import -#import -#import + +#import +#import +#import +#import +#import +#import +#import +#import #import #import // 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]; diff --git a/UI/MailerUI/Ukrainian.lproj/Localizable.strings b/UI/MailerUI/Ukrainian.lproj/Localizable.strings index 7ff93d679..80d5cf2c9 100644 --- a/UI/MailerUI/Ukrainian.lproj/Localizable.strings +++ b/UI/MailerUI/Ukrainian.lproj/Localizable.strings @@ -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" = "Найвища"; diff --git a/UI/MailerUI/Welsh.lproj/Localizable.strings b/UI/MailerUI/Welsh.lproj/Localizable.strings index 900781413..85088ef6f 100644 --- a/UI/MailerUI/Welsh.lproj/Localizable.strings +++ b/UI/MailerUI/Welsh.lproj/Localizable.strings @@ -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"; diff --git a/UI/MailerUI/product.plist b/UI/MailerUI/product.plist index abd4c0c67..6d6cc0380 100644 --- a/UI/MailerUI/product.plist +++ b/UI/MailerUI/product.plist @@ -213,6 +213,11 @@ protectedBy = "View"; pageName = "UIxMailView"; }; + sendMDN = { + protectedBy = "View"; + pageName = "UIxMailView"; + actionName = "sendMDN"; + }; viewsource = { protectedBy = "View"; actionClass = "UIxMailSourceView"; diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index 1b8e76593..ecf2909f0 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -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]; diff --git a/UI/Templates/MailerUI/UIxMailView.wox b/UI/Templates/MailerUI/UIxMailView.wox index 78fdcec03..7c8dce1ad 100644 --- a/UI/Templates/MailerUI/UIxMailView.wox +++ b/UI/Templates/MailerUI/UIxMailView.wox @@ -5,6 +5,7 @@ xmlns:uix="OGo:uix" xmlns:rsrc="OGo:url" xmlns:label="OGo:label"> + - - diff --git a/UI/Templates/PreferencesUI/UIxPreferences.wox b/UI/Templates/PreferencesUI/UIxPreferences.wox index c1fa54c47..e0c903700 100644 --- a/UI/Templates/PreferencesUI/UIxPreferences.wox +++ b/UI/Templates/PreferencesUI/UIxPreferences.wox @@ -225,31 +225,71 @@

-
- - - -
+
+
+
+ + +



+
+ +
+
+
+
+
+ +
+ + +
+ + +
+
+
diff --git a/UI/WebServerResources/JavascriptAPIExtensions.js b/UI/WebServerResources/JavascriptAPIExtensions.js index f0dda1572..e559b759e 100644 --- a/UI/WebServerResources/JavascriptAPIExtensions.js +++ b/UI/WebServerResources/JavascriptAPIExtensions.js @@ -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) { diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index aba747238..109a65dc3 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -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; diff --git a/UI/WebServerResources/UIxMailPopupView.js b/UI/WebServerResources/UIxMailPopupView.js index 311f9ef1d..f1b370664 100644 --- a/UI/WebServerResources/UIxMailPopupView.js +++ b/UI/WebServerResources/UIxMailPopupView.js @@ -14,6 +14,8 @@ function initPopupMailer(event) { configureSignatureFlagImage(); window.messageUID = mailboxName + "/" + messageName; + + handleReturnReceipt(); } function onICalendarButtonClick(event) { diff --git a/UI/WebServerResources/UIxPreferences.css b/UI/WebServerResources/UIxPreferences.css index 59b6366cc..174515c9e 100644 --- a/UI/WebServerResources/UIxPreferences.css +++ b/UI/WebServerResources/UIxPreferences.css @@ -190,3 +190,6 @@ P.infoMessage#passwordError height: 90px; margin: 0px auto; margin-bottom: 10px; } + +#receiptOptions +{ text-align: right; } diff --git a/UI/WebServerResources/UIxPreferences.js b/UI/WebServerResources/UIxPreferences.js index 61beb4996..56f47b640 100644 --- a/UI/WebServerResources/UIxPreferences.js +++ b/UI/WebServerResources/UIxPreferences.js @@ -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) {