merge of 'c31687d1f15f8f1be580514cd252776e204a1b65'

and 'd44c77e73da2480ce01afa441c8a2705f220ae25'

Monotone-Parent: c31687d1f15f8f1be580514cd252776e204a1b65
Monotone-Parent: d44c77e73da2480ce01afa441c8a2705f220ae25
Monotone-Revision: 701785bc094e6e0cc71468721c162b7ddd82fda5

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2008-09-30T16:50:07
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2008-09-30 16:50:07 +00:00
commit 95ee964274
34 changed files with 425 additions and 129 deletions

122
ChangeLog
View File

@ -5,9 +5,23 @@
lookup syntax has been generalized by testing for "ref-dn" instead
of "dict-dn". Make use of only non-deprecated LDAP functions.
2008-09-30 Cyril Robert <crobert@inverse.ca>
* SoObjects/Mailer/SOGoDraftsFolder.m
Moved userSpoolFolderPath method to SOGoMailFolder.m
* SoObjects/Mailer/SOGoMailFolder.h
* SoObjects/Mailer/SOGoMailFolder.m
Added userSpoolFolderPath from SOGoDraftsFolder
Added archiveUIDs method to create an archive from email uids
* UI/MailerUI/UIxMailFolderActions.h
* UI/MailerUI/UIxMailFolderActions.m
Added saveMessagesAction method to handle the /saveMessages call
* UI/MailerUI/product.plist
Added a definition for saveMessages
2008-09-28 Ludovic Marcotte <lmarcotte@inverse.ca>
* Modified the following files:
* Modified the following files:
SoObjects/Mailer/SOGoDraftObject.m
UI/MailerUI/Dutch.lproj/Localizable.strings
UI/MailerUI/English.lproj/Localizable.strings
@ -329,7 +343,7 @@
2008-08-22 Ludovic Marcotte <lmarcotte@inverse.ca>
* Modified SoObjects/Mailer/NSData+Mail.m
* Modified SoObjects/Mailer/NSData+Mail.m
-decodedSubject so we correctly implement decoding
instead of relying on the broken SOPE implementation.
@ -1679,14 +1693,14 @@
2008-01-14 Ludovic Marcotte <ludovic@inverse.ca>
* Added files related to the custom recurrence
editor of the SOGo Web interface. The CSS
needs to be done correctly.
editor of the SOGo Web interface. The CSS
needs to be done correctly.
* Fixed a bug in the daily recurrence generator.
We now consider the byDayMask, if any.
We now consider the byDayMask, if any.
* Moved the repeat/reminder code to the
UIxComponentEditor class / template.
UIxComponentEditor class / template.
* Added a few JavaScript methods to HTMLElement.js
@ -1828,7 +1842,7 @@
and created re-entrant issues.
* UI/MailPartViewers/UIxMailPartHTMLViewer.m
Added a hack (and stated so in the source file)
Added a hack (and stated so in the source file)
to avoid what seems to be a bug in libxml.
2007-12-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
@ -2141,32 +2155,32 @@
2007-11-25 Ludovic Marcotte <ludovic@inverse.ca>
* SoObjects/Mailer/SOGoMailForward.m
Use [sourceMail decodedSubject] instead of [sourceMail subject]
Signature fix in -signature - see the comment
for SOGoMailReply.
* SoObjects/Mailer/SOGoMailForward.m
Use [sourceMail decodedSubject] instead of [sourceMail subject]
Signature fix in -signature - see the comment
for SOGoMailReply.
* SoObjects/Mailer/SOGoMailObject.m
Improved -stringFromData: to try UTF-8 then fallback to Latin1
* SoObjects/Mailer/SOGoMailObject.m
Improved -stringFromData: to try UTF-8 then fallback to Latin1
* SoObjects/Mailer/SOGoMailReply.m
Modified -messageBody to strip the signature from the reply.
Also modified -signature to add "-- \n%@" instead of the
broken ""--\r\n%@" pattern.
* SoObjects/Mailer/SOGoMailReply.m
Modified -messageBody to strip the signature from the reply.
Also modified -signature to add "-- \n%@" instead of the
broken ""--\r\n%@" pattern.
* UI/MailPartViewers/UIxMailPartAlternativeViewer.m
We now favor text/calendar parts over text/html and
text/plain parts when viewing a multipart/alternative mail.
This allows us to show the email invitations coming from
Microsoft Outlook.
* UI/MailPartViewers/UIxMailPartAlternativeViewer.m
We now favor text/calendar parts over text/html and
text/plain parts when viewing a multipart/alternative mail.
This allows us to show the email invitations coming from
Microsoft Outlook.
* UI/MailerUI/UIxMailAccountActions.m
Signature fix in -composeAction - see the comment
for SOGoMailReply.
* UI/MailerUI/UIxMailAccountActions.m
Signature fix in -composeAction - see the comment
for SOGoMailReply.
* UI/MailPartViewers/UIxMailPartViewer.m
Modified -flatContentAsString to use UTF-8 as the
default fallback encoding for 8-bit content.
* UI/MailPartViewers/UIxMailPartViewer.m
Modified -flatContentAsString to use UTF-8 as the
default fallback encoding for 8-bit content.
* SoObjects/Mailer/SOGoDraftObject.m
Modified _fillInReplyAddresses:replyToAll:envelope:
@ -2427,7 +2441,7 @@
2007-11-16 Ludovic Marcotte <ludovic@inverse.ca>
* SoObjects/Mailer/SOGoMailBaseObject.m
* SoObjects/Mailer/SOGoMailBaseObject.m
Fixed typo.
* SoObjects/Mailer/SOGoMailBodyPart.m
@ -2455,27 +2469,27 @@
2007-11-15 Ludovic Marcotte <ludovic@inverse.ca>
* UI/WebServerResources/MailerUI.js
We now check for empty selection and warn the
user about it when deleting messages
* UI/WebServerResources/MailerUI.js
We now check for empty selection and warn the
user about it when deleting messages
* SoObjects/Mailer/SOGoDraftObject.m
Correctly check for the presence of a subject
before attempting to forward a message from
the Drafts folder.
* SoObjects/Mailer/SOGoDraftObject.m
Correctly check for the presence of a subject
before attempting to forward a message from
the Drafts folder.
* SoObjects/Mailer/SOGoMailObject+Draft.m
We no longer use "[Fwd: ]" but simply "Fwd:"
when forwarding email messages.
* SoObjects/Mailer/SOGoMailObject+Draft.m
We no longer use "[Fwd: ]" but simply "Fwd:"
when forwarding email messages.
* SoObjects/SOGo/SOGoUser.m
Modified the default forwarding format to be
inline instead of "attachment".
* SoObjects/SOGo/SOGoUser.m
Modified the default forwarding format to be
inline instead of "attachment".
* SoObjects/Mailer/SOGoDraftObject.m
We now create and use a NGMimeContentDispositionHeaderField
in order to avoid encoding the whole Content-Disposition
header in case a non-ASCII char is present!
* SoObjects/Mailer/SOGoDraftObject.m
We now create and use a NGMimeContentDispositionHeaderField
in order to avoid encoding the whole Content-Disposition
header in case a non-ASCII char is present!
2007-11-13 Wolfgang Sourdeau <wsourdeau@inverse.ca>
@ -3118,10 +3132,10 @@
2007-10-10 Ludovic Marcotte <ludovic@inverse.ca>
* We now send advisory emails when folders
are created / deleted.
are created / deleted.
* Fixed the sending of advisory emails upon
ACL changes on folders.
ACL changes on folders.
2007-10-10 Ludovic Marcotte <ludovic@inverse.ca>
@ -3137,7 +3151,7 @@
in every LDAP-based authentication sources.
* UI/MailPartViewers/UIxMailPartTextViewer.m and
UI/WebServerResources/MailerUI.css
UI/WebServerResources/MailerUI.css
We avoid replacing "\r\n" and "\n" with <br /> and
rather use CSS capabilities for proper formatting.
This is _WAY_ faster on very large mails.
@ -5448,10 +5462,10 @@
2007-02-09 Helge Hess <helge.hess@opengroupware.org>
* SoObjects/Appointments/SOGoAppointmentFolder.m: added CalDAV
resourcetype
resourcetype
* SoObjects/SOGo/SOGoUserFolder.m: added davCalendarHomeSet CalDAV
property to point at the user folder
property to point at the user folder
2007-03-07 Wolfgang Sourdeau <wsourdeau@inverse.ca>
@ -7525,9 +7539,9 @@
2006-06-15 ludovic@inverse.ca
* It's now possible to set the default
domain using for email using the
SOGoDefaultMailDomain preference key.
* It's now possible to set the default
domain using for email using the
SOGoDefaultMailDomain preference key.
2006-06-15 ludovic@inverse.ca

5
NEWS
View File

@ -1,3 +1,8 @@
1.0-2008XXYY (1.0)
------------------
- added quota indicator in web mail module
- improved drag handles behavior
1.0-20080826 (1.0 rc8)
----------------------
- fixed a bug that would prevent deleted event and tasks from being removed from the events and tasks list

View File

@ -47,7 +47,7 @@ static unsigned int newCount;
ud = [NSUserDefaults standardUserDefaults];
spoolFolder = [ud stringForKey:@"SOGoMailSpoolPath"];
if (![spoolFolder length])
spoolFolder = @"/tmp/";
spoolFolder = @"/tmp/";
[spoolFolder retain];
NSLog(@"Note: using SOGo mail spool folder: %@", spoolFolder);
@ -102,14 +102,5 @@ static unsigned int newCount;
return YES;
}
- (NSString *) userSpoolFolderPath
{
NSString *login;
login = [[context activeUser] login];
return [NSString stringWithFormat: @"%@/%@",
spoolFolder, login];
}
@end

View File

@ -1,3 +1,8 @@
<#signaturePlacementOnTop>
<#signature/>
</#signaturePlacementOnTop>
<#outlookMode>-------- Original Message --------
Subject: <#subject/>
Date: <#date/>
@ -8,4 +13,5 @@ From: <#from/>
<#messageBody/>
<#signature/>
<#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom>

View File

@ -81,3 +81,21 @@ signature: WOString {
value = signature;
escapeHTML = NO;
}
replyPlacementOnTop: WOConditional {
condition = replyPlacementOnTop;
}
replyPlacementOnBottom: WOConditional {
condition = replyPlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View File

@ -24,6 +24,7 @@
#include <SoObjects/Mailer/SOGoMailBaseObject.h>
#import <Foundation/NSRange.h>
#import <NGObjWeb/WOResponse.h>
/*
SOGoMailFolder
@ -55,6 +56,7 @@ typedef enum {
/* messages */
- (NSException *) deleteUIDs: (NSArray *) uids inContext: (id) context;
- (WOResponse *) archiveUIDs: (NSArray *) uids inContext: (id) context;
- (NSArray *) fetchUIDsMatchingQualifier: (id)_q sortOrdering: (id) _so;
- (NSArray *) fetchUIDs: (NSArray *) _uids parts: (NSArray *) _parts;
@ -81,6 +83,9 @@ typedef enum {
- (NSArray *) allFolderPaths;
- (NSArray *) allFolderURLs;
- (NSString *) userSpoolFolderPath;
- (BOOL) ensureSpoolFolderPath;
@end
@interface SOGoSpecialMailFolder : SOGoMailFolder

View File

@ -23,13 +23,16 @@
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSTask.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSURL+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSFileManager+Extensions.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Client.h>
@ -51,6 +54,8 @@ static BOOL aclUsernamesAreQuoted = NO;
/* http://www.tools.ietf.org/wg/imapext/draft-ietf-imapext-acl/ */
static BOOL aclConformsToIMAPExt = NO;
static NSString *spoolFolder = nil;
@interface NGImap4Connection (PrivateMethods)
- (NSString *) imap4FolderNameForURL: (NSURL *) url;
@ -65,19 +70,29 @@ static BOOL aclConformsToIMAPExt = NO;
NSString *aclStyleStr;
if (aclStyle == undefined)
{
ud = [NSUserDefaults standardUserDefaults];
aclStyleStr = [ud stringForKey: @"SOGoIMAPAclStyle"];
if ([aclStyleStr isEqualToString: @"rfc2086"])
aclStyle = rfc2086;
else
aclStyle = rfc4314;
{
ud = [NSUserDefaults standardUserDefaults];
aclStyleStr = [ud stringForKey: @"SOGoIMAPAclStyle"];
if ([aclStyleStr isEqualToString: @"rfc2086"])
aclStyle = rfc2086;
else
aclStyle = rfc4314;
aclUsernamesAreQuoted
= [ud boolForKey: @"SOGoIMAPAclUsernamesAreQuoted"];
aclConformsToIMAPExt
= [ud boolForKey: @"SOGoIMAPAclConformsToIMAPExt"];
}
aclUsernamesAreQuoted
= [ud boolForKey: @"SOGoIMAPAclUsernamesAreQuoted"];
aclConformsToIMAPExt
= [ud boolForKey: @"SOGoIMAPAclConformsToIMAPExt"];
}
if (!spoolFolder)
{
spoolFolder = [ud stringForKey:@"SOGoMailSpoolPath"];
if (![spoolFolder length])
spoolFolder = @"/tmp/";
[spoolFolder retain];
NSLog(@"Note: using SOGo mail spool folder: %@", spoolFolder);
}
}
+ (SOGoIMAPAclStyle) imapAclStyle
@ -302,6 +317,82 @@ static BOOL aclConformsToIMAPExt = NO;
return error;
}
- (WOResponse *) archiveUIDs: (NSArray *) uids
inContext: (id) localContext
{
NSException *error;
NSFileManager *fm;
NSString *spoolPath, *fileName;
NSDictionary *msgs;
NSArray *messages;
NSData *content, *zipContent;
NSTask *zipTask;
NSMutableArray *zipTaskArguments;
WOResponse *response;
int i;
spoolPath = [self userSpoolFolderPath];
if ( ![self ensureSpoolFolderPath] ) {
error = [NSException exceptionWithHTTPStatus: 500
reason: @"spoolFolderPath doesn't exist"];
return (WOResponse *)error;
}
fm = [NSFileManager defaultManager];
if ( ![fm fileExistsAtPath: @"/usr/bin/zip"] ) {
error = [NSException exceptionWithHTTPStatus: 500
reason: @"zip not available"];
return (WOResponse *)error;
}
zipTask = [[NSTask alloc] init];
[zipTask setCurrentDirectoryPath: spoolPath];
[zipTask setLaunchPath: @"/usr/bin/zip"];
zipTaskArguments = [NSMutableArray arrayWithObjects: nil];
[zipTaskArguments addObject: @"SavedMessages.zip"];
msgs = (NSDictionary *)[self fetchUIDs: uids
parts: [NSArray arrayWithObject: @"RFC822"]];
messages = [msgs objectForKey: @"fetch"];
for (i = 0; i < [messages count]; i++) {
content = [[messages objectAtIndex: i] objectForKey: @"message"];
[content writeToFile:
[NSString stringWithFormat:@"%@/%d.eml", spoolPath, [uids objectAtIndex: i]]
atomically: YES];
[zipTaskArguments addObject:
[NSString stringWithFormat:@"%d.eml", [uids objectAtIndex: i]]];
}
[zipTask setArguments: zipTaskArguments];
[zipTask launch];
[zipTask waitUntilExit];
[zipTask release];
zipContent = [[NSData alloc] initWithContentsOfFile:
[NSString stringWithFormat: @"%@/SavedMessages.zip", spoolPath]];
for(i = 0; i < [zipTaskArguments count]; i++) {
fileName = [zipTaskArguments objectAtIndex: i];
[fm removeFileAtPath:
[NSString stringWithFormat: @"%@/%@", spoolPath, fileName] handler: nil];
}
response = [[WOResponse alloc] init];
[response autorelease];
[response setHeader: @"application/zip" forKey:@"content-type"];
[response setHeader: @"attachment;filename=SavedMessages.zip" forKey: @"Content-Disposition"];
[response setContent: zipContent];
[zipContent release];
return response;
}
- (NSArray *) fetchUIDsMatchingQualifier: (id) _q
sortOrdering: (id) _so
{
@ -891,6 +982,25 @@ static BOOL aclConformsToIMAPExt = NO;
return [userURL absoluteString];
}
- (NSString *) userSpoolFolderPath
{
NSString *login;
login = [[context activeUser] login];
return [NSString stringWithFormat: @"%@/%@",
spoolFolder, login];
}
- (BOOL) ensureSpoolFolderPath
{
NSFileManager *fm;
fm = [NSFileManager defaultManager];
return ([fm createDirectoriesAtPath: [self userSpoolFolderPath] attributes:nil]);
}
@end /* SOGoMailFolder */
@implementation SOGoSpecialMailFolder

View File

@ -1,3 +1,8 @@
<#signaturePlacementOnTop>
<#signature/>
</#signaturePlacementOnTop>
<#outlookMode>-------- Message original --------
Sujet: <#subject/>
Date: <#date/>
@ -8,4 +13,5 @@ De: <#from/>
<#messageBody/>
<#signature/>
<#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom>

View File

@ -81,3 +81,21 @@ signature: WOString {
value = signature;
escapeHTML = NO;
}
replyPlacementOnTop: WOConditional {
condition = replyPlacementOnTop;
}
replyPlacementOnBottom: WOConditional {
condition = replyPlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View File

@ -1,3 +1,8 @@
<#signaturePlacementOnTop>
<#signature/>
</#signaturePlacementOnTop>
<#outlookMode>-------- Original E-Mail --------
Betreff: <#subject/>
Datum: <#date/>
@ -8,4 +13,5 @@ Sender: <#from/>
<#messageBody/>
<#signature/>
<#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom>

View File

@ -81,3 +81,21 @@ signature: WOString {
value = signature;
escapeHTML = NO;
}
replyPlacementOnTop: WOConditional {
condition = replyPlacementOnTop;
}
replyPlacementOnBottom: WOConditional {
condition = replyPlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View File

@ -1,3 +1,8 @@
<#signaturePlacementOnTop>
<#signature/>
</#signaturePlacementOnTop>
<#outlookMode>-------- Messaggio originale --------
Oggetto: <#subject/>
Data: <#date/>
@ -8,4 +13,5 @@ Da: <#from/>
<#messageBody/>
<#signature/>
<#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom>

View File

@ -81,3 +81,21 @@ signature: WOString {
value = signature;
escapeHTML = NO;
}
replyPlacementOnTop: WOConditional {
condition = replyPlacementOnTop;
}
replyPlacementOnBottom: WOConditional {
condition = replyPlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View File

@ -1,3 +1,8 @@
<#signaturePlacementOnTop>
<#signature/>
</#signaturePlacementOnTop>
<#outlookMode>-------- Original Message --------
Subject: <#subject/>
Date: <#date/>
@ -8,4 +13,5 @@ From: <#from/>
<#messageBody/>
<#signature/>
<#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom>

View File

@ -81,3 +81,21 @@ signature: WOString {
value = signature;
escapeHTML = NO;
}
replyPlacementOnTop: WOConditional {
condition = replyPlacementOnTop;
}
replyPlacementOnBottom: WOConditional {
condition = replyPlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View File

@ -209,7 +209,7 @@
"Operation failed" = "Operatie mislukt.";
"Quota" = "Quota";
"quotasFormat" = "%{0} van %{1} KB gebruikt (%{2}%)";
"quotasFormat" = "%{0}% van %{1} MB gebruikt";
"Please select a message." = "Selecteer een bericht.";
"Please select a message to print." = "Selecteer een bericht om af te drukken.";

View File

@ -223,8 +223,8 @@
= "Do you really want to move this folder into the trash ?";
"Operation failed" = "Operation failed";
"Quota" = "Quota";
"quotasFormat" = "%{0} used on %{1} Kb (%{2}%)";
"Quota" = "Quota:";
"quotasFormat" = "%{0}% used on %{1} MB";
"Please select a message." = "Please select a message.";
"Please select a message to print." = "Please select a message to print.";

View File

@ -226,7 +226,7 @@
"Operation failed" = "L'opération a échoué.";
"Quota" = "Quota";
"quotasFormat" = "%{0} Ko utilisés sur %{1} (%{2}%)";
"quotasFormat" = "%{0}% utilisé sur %{1} MO";
"Please select a message." = "Veuillez sélectionner un message.";
"Please select a message to print." = "Veuillez sélectionner un message à imprimer.";

View File

@ -209,7 +209,7 @@
"Operation failed" = "L'opération a échoué.";
"Quota" = "Quota";
"quotasFormat" = "%{0} von %{1} KB verwendet (%{2}%)";
"quotasFormat" = "%{0}% von %{1} MB verwendet";
"Please select a message." = "Sie müssen eine Nachricht auswählen.";
"Please select a message to print." = "Sie müssen eine Nachricht zum Drucken auswählen.";

View File

@ -232,7 +232,7 @@
"Operation failed" = "Operazione non riuscita";
"Quota" = "Spazio usato";
"quotasFormat" = "%{0} su %{1} Kb (%{2}%)";
"quotasFormat" = "%{0}% usato su %{1} MB";
"Please select a message." = "Per favore seleziona un messaggio.";
"Please select a message to print." = "Per favore seleziona un messaggio da stampare.";

View File

@ -228,7 +228,7 @@
"Operation failed" = "Operación fallida";
"Quota" = "Quotas";
"quotasFormat" = "%{0} de %{1} Kb usados (%{2}%)";
"quotasFormat" = "%{0}% de %{1} MB usados";
"Please select a message." = "Seleccione un mensaje primero.";
"Please select a message to print." = "Seleccione el mensaje que desea imprimir.";

View File

@ -134,7 +134,7 @@
NSString *inboxName;
NSUserDefaults *ud;
WOResponse *response;
int quota;
float quota;
ud = [NSUserDefaults standardUserDefaults];
co = [self clientObject];
@ -143,18 +143,21 @@
folders = [self _jsonFolders: rawFolders];
// Retrieve INBOX quota
quota = [ud integerForKey: @"SOGoSoftQuota"];
quota = [ud floatForKey: @"SOGoSoftQuotaRatio"];
inbox = [co inboxFolderInContext: context];
inboxName = [NSString stringWithFormat: @"/%@", [inbox relativeImap4Name]];
client = [[inbox imap4Connection] client];
infos = [[client getQuotaRoot: [inbox relativeImap4Name]] objectForKey: @"quotas"];
inboxQuota = [infos objectForKey: inboxName];
if (quota > 0 && inboxQuota != nil)
// A soft quota is imposed for all users
inboxQuota = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: quota], @"maxQuota",
[inboxQuota objectForKey: @"usedSpace"], @"usedSpace",
nil];
if (quota != 0 && inboxQuota != nil)
{
// A soft quota ration is imposed for all users
quota = quota * [(NSNumber*)[inboxQuota objectForKey: @"maxQuota"] intValue];
inboxQuota = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: (long)(quota+0.5)], @"maxQuota",
[inboxQuota objectForKey: @"usedSpace"], @"usedSpace",
nil];
}
data = [NSDictionary dictionaryWithObjectsAndKeys: folders, @"mailboxes",
inboxQuota, @"quotas",
nil];

View File

@ -33,6 +33,7 @@
- (WOResponse *) renameFolderAction;
- (WOResponse *) deleteFolderAction;
- (WOResponse *) deleteMessagesAction;
- (WOResponse *) saveMessagesAction;
- (WOResponse *) expungeAction;
- (WOResponse *) emptyTrashAction;
- (WOResponse *) subscribeAction;

View File

@ -209,6 +209,33 @@
return response;
}
- (WOResponse *) saveMessagesAction
{
SOGoMailFolder *co;
WOResponse *response;
NSArray *uids;
NSString *value;
co = [self clientObject];
value = [[context request] formValueForKey: @"uid"];
response = nil;
if ([value length] > 0)
{
uids = [value componentsSeparatedByString: @","];
response = [co archiveUIDs: uids inContext: context];
if (!response)
response = [self responseWith204];
}
else
{
response = [self responseWithStatus: 500];
[response appendContentString: @"Missing 'uid' parameter."];
}
return response;
}
- (WOResponse *) _setFolderPurpose: (NSString *) purpose
{
SOGoMailFolder *co;

View File

@ -20,7 +20,6 @@
*/
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSValue.h>
#import <NGCards/NGVCard.h>
@ -150,8 +149,8 @@
- (id <WOActionResults>) composeAction
{
id <SOGoContactObject> contact;
NSArray *accounts, *contactsId;
NSString *firstAccount, *newLocation, *parameters, *folderId, *uid, *email, *n;
NSArray *accounts, *contactsId, *n;
NSString *firstAccount, *newLocation, *parameters, *folderId, *uid, *email;
NSMutableString *fn;
NSEnumerator *uids;
NSMutableArray *addresses;

View File

@ -141,6 +141,11 @@
actionClass = "UIxMailFolderActions";
actionName = "deleteMessages";
};
saveMessages = {
protectedBy = "View";
actionClass = "UIxMailFolderActions";
actionName = "saveMessages";
};
setAsDraftsFolder = {
protectedBy = "View";
actionClass = "UIxMailFolderActions";

View File

@ -124,6 +124,7 @@
<li><var:string label:value="Label"/></li>
<li><var:string label:value="Mark"/></li>
<li><!-- separator --></li>
<li><var:string label:value="Save As..."/></li>
<li><var:string label:value="Print Preview"/></li>
<li><var:string label:value="Print..."/></li>
<li><var:string label:value="Delete Selected Messages"/></li>
@ -191,13 +192,6 @@
</ul>
</div>
<div id="quotaDialog" style="display: none;">
<div>
<h1><var:string label:value="Quota"/></h1>
<p><!-- space --></p>
</div>
</div>
<div id="leftPanel">
<div class="titlediv"><var:string label:value="Folders" /></div>
<div id="folderTreeContent"><!-- space --></div>

View File

@ -650,7 +650,7 @@ DIV.quota DIV.level
background-position: 25% 0;
border-left: 1px solid #999;
border-right: 1px solid #999;
height: 20px; }
/*height: 20px;*/ }
DIV.quota DIV.marks DIV
{ float: left;
margin: 0;
@ -658,11 +658,11 @@ DIV.quota DIV.marks DIV
width: 25%;
border: 0;
border-right: 1px solid #999;
height: 5px; }
height: 3px; }
DIV.quota DIV.level DIV.value
{ background-repeat: repeat-x;
border-left: 1px solid transparent;
height: 15px;
height: 9px;
margin: 0;
position: relative; }
DIV.quota DIV.level DIV.value.ok
@ -670,7 +670,15 @@ DIV.quota DIV.level DIV.value.ok
DIV.quota DIV.level DIV.value.warn
{ background-image: url(quota-level-warn.png); }
DIV.quota DIV.level DIV.value.alert
{ background-image: url(quota-level-alert.png); }
{ background-image: url(quota-level-alert.png); }
DIV.quota DIV.level P
{ margin: 0;
padding: 0;
clear: both;
color: #555;
font-size: 1em;
text-align: center;
}
DIV#quotaDialog
{ background-image: url("dialog-left.png");
background-repeat: no-repeat;

View File

@ -1373,39 +1373,29 @@ function updateMailboxTreeInPage() {
}
}
if (Mailer.quotas) {
// Build quota indicator
// Build quota indicator, show values in MB
var percents = (Math.round(Mailer.quotas.usedSpace * 10000 / Mailer.quotas.maxQuota) / 100);
var level = (percents > 85)? "alert" : (percents > 70)? "warn" : "ok";
var format = labels["quotasFormat"];
var text = format.formatted(Mailer.quotas.usedSpace, Mailer.quotas.maxQuota, percents);
var text = format.formatted(percents,
Math.round(Mailer.quotas.maxQuota/10.24)/100);
var quotaDiv = new Element('div', { 'class': 'quota', 'info': text });
var levelDiv = new Element('div', { 'class': 'level' });
var valueDiv = new Element('div', { 'class': 'value ' + level, 'style': 'width: ' + ((percents > 100)?100:percents) + '%' });
var marksDiv = new Element('div', { 'class': 'marks' });
var textP = new Element('p').update(text);
marksDiv.appendChild(new Element('div'));
marksDiv.appendChild(new Element('div'));
marksDiv.appendChild(new Element('div'));
levelDiv.appendChild(valueDiv);
levelDiv.appendChild(marksDiv);
levelDiv.appendChild(textP);
quotaDiv.appendChild(levelDiv);
treeContent.insertBefore(quotaDiv, tree);
quotaDiv.observe("mouseover", onViewQuota);
quotaDiv.observe("mouseout", function(event) { $("quotaDialog").hide(); });
}
}
function onViewQuota(event) {
var div = $("quotaDialog");
if (div.visible()) return;
var position = this.cumulativeOffset();
position[0] += this.getWidth();
div.down("p").update(this.readAttribute("info"));
div.setStyle({ left: position[0] + "px",
top: position[1] + "px" });
div.show();
}
function mailboxMenuNode(type, name) {
var newNode = document.createElement("li");
var icon = MailerUIdTreeExtension.folderIcons[type];
@ -1840,6 +1830,28 @@ function onLabelMenuPrepareVisibility() {
lis[0].addClassName("_chosen");
}
function saveAs(event) {
var messageList = $("messageList").down("TBODY");
var rows = messageList.getSelectedNodes();
var uids = new Array(); // message IDs
var paths = new Array(); // row IDs
if (rows.length > 0) {
for (var i = 0; i < rows.length; i++) {
var uid = rows[i].readAttribute("id").substr(4);
var path = Mailer.currentMailbox + "/" + uid;
uids.push(uid);
paths.push(path);
}
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/saveMessages";
window.open(url+"?id="+uids+"&uid="+uids+"&mailbox="+Mailer.currentMailbox+"&path="+paths);
}
else
window.alert(labels["Please select a message."]);
return false;
}
function getMenus() {
var menus = {}
menus["accountIconMenu"] = new Array(null, null, onMenuCreateFolder, null,
@ -1867,14 +1879,14 @@ function getMenus() {
onMenuForwardMessage, null,
"-", "moveMailboxMenu",
"copyMailboxMenu", "label-menu",
"mark-menu", "-", null,
"mark-menu", "-", saveAs,
onMenuViewMessageSource, null,
null, onMenuDeleteMessage);
menus["messagesListMenu"] = new Array(onMenuForwardMessage,
"-", "moveMailboxMenu",
"copyMailboxMenu", "label-menu",
"mark-menu", "-",
null, null,
saveAs, null,
onMenuDeleteMessage);
menus["imageMenu"] = new Array(saveImage);
menus["messageContentMenu"] = new Array(onMenuReplyToSender,
@ -1884,7 +1896,7 @@ function getMenus() {
"copyMailboxMenu",
"-", "label-menu", "mark-menu",
"-",
null, onMenuViewMessageSource,
saveAs, onMenuViewMessageSource,
null, onPrintCurrentMessage,
onMenuDeleteMessage);
menus["folderTypeMenu"] = new Array(onMenuChangeToSentFolder,

View File

@ -539,7 +539,9 @@ function initMailEditor() {
var sigLimit = textContent.lastIndexOf("--");
if (sigLimit > -1)
signatureLength = (textContent.length - sigLimit);
textarea.scrollTop = textarea.scrollHeight;
if ( userDefaults["ReplyPlacement"] != "above" ) {
textarea.scrollTop = textarea.scrollHeight;
}
textarea.observe("focus", onTextFirstFocus);
textarea.observe("focus", onTextFocus);
// textarea.observe("contextmenu", onTextContextMenu);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB