See ChangeLog
Monotone-Parent: 73de56ded7f5b5ba79857c706ecef4d70ac3113b Monotone-Revision: 5c6353cb6270d51a457d46a8fe98dadae4f37193 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2011-07-07T13:58:50 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
485e53258f
commit
34f2904f0d
18
ChangeLog
18
ChangeLog
|
@ -1,3 +1,21 @@
|
|||
2011-07-08 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/MailerUI/UIxMailListActions.m (-getUIDsAndHeadersInFolder)
|
||||
(-getSortedUIDsAction): both methods now return the inbox quota
|
||||
along with the other data.
|
||||
|
||||
* UI/MailerUI/UIxMailFolderActions.m (-batchDeleteAction): return
|
||||
the inbox quota when the messages were successfully deleted.
|
||||
|
||||
* SoObjects/Mailer/SOGoMailFolder.m
|
||||
(-deleteUIDs:useTrashFolder:inContext:): when not using the trash folder
|
||||
or when deleting a message within the trash folder, we now expunge the
|
||||
folder immediately.
|
||||
|
||||
* UI/WebServerResources/SOGoMailDataSource.js (init): quotas
|
||||
information can now be passed as argument. It will be passed back
|
||||
to the method "updateQuotas" from MailerUI.js.
|
||||
|
||||
2011-07-08 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* OpenChange/MAPIStoreContext.m (-openDir:): implemented.
|
||||
|
|
|
@ -296,7 +296,11 @@ static NSString *defaultUserID = @"anyone";
|
|||
|
||||
// If we are deleting messages within the Trash folder itself, we
|
||||
// do not, of course, try to move messages to the Trash folder.
|
||||
if (![folderName isEqualToString: [self relativeImap4Name]])
|
||||
if ([folderName isEqualToString: [self relativeImap4Name]])
|
||||
{
|
||||
withTrash = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If our Trash folder doesn't exist when we try to copy messages
|
||||
// to it, we create it.
|
||||
|
@ -330,12 +334,21 @@ static NSString *defaultUserID = @"anyone";
|
|||
forUIDs: uids addOrRemove: YES]
|
||||
objectForKey: @"result"];
|
||||
if ([result boolValue])
|
||||
{
|
||||
if (withTrash)
|
||||
{
|
||||
[self markForExpunge];
|
||||
if (trashFolder)
|
||||
[trashFolder flushMailCaches];
|
||||
error = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
// When not using a trash folder, expunge the current folder
|
||||
// immediately
|
||||
error = [self expunge];
|
||||
}
|
||||
}
|
||||
else
|
||||
error
|
||||
= [NSException exceptionWithHTTPStatus:500
|
||||
|
|
|
@ -181,13 +181,11 @@
|
|||
NSArray *folders;
|
||||
NSDictionary *data;
|
||||
WOResponse *response;
|
||||
id inboxQuota;
|
||||
|
||||
co = [self clientObject];
|
||||
|
||||
rawFolders = [[co allFolderPaths] objectEnumerator];
|
||||
folders = [self _jsonFolders: rawFolders];
|
||||
inboxQuota = nil;
|
||||
|
||||
// The parameters order is important here, as if the server doesn't support
|
||||
// quota, inboxQuota will be nil and it'll terminate the list of objects/keys.
|
||||
|
|
|
@ -229,9 +229,11 @@
|
|||
- (WOResponse *) batchDeleteAction
|
||||
{
|
||||
SOGoMailFolder *co;
|
||||
SOGoMailAccount *account;
|
||||
WOResponse *response;
|
||||
NSArray *uids;
|
||||
NSString *value;
|
||||
NSDictionary *data;
|
||||
BOOL withoutTrash;
|
||||
|
||||
co = [self clientObject];
|
||||
|
@ -244,7 +246,12 @@
|
|||
uids = [value componentsSeparatedByString: @","];
|
||||
response = (WOResponse *) [co deleteUIDs: uids useTrashFolder: !withoutTrash inContext: context];
|
||||
if (!response)
|
||||
response = [self responseWith204];
|
||||
{
|
||||
account = [co mailAccountFolder];
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys: [account getInboxQuota], @"quotas", nil];
|
||||
response = [self responseWithStatus: 200
|
||||
andString: [data jsonRepresentation]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -520,6 +527,8 @@
|
|||
if (!error)
|
||||
{
|
||||
[co flushMailCaches];
|
||||
|
||||
// Delete folders within the trash
|
||||
connection = [co imap4Connection];
|
||||
subfolders = [[co allFolderURLs] objectEnumerator];
|
||||
while ((currentURL = [subfolders nextObject]))
|
||||
|
@ -585,6 +594,7 @@
|
|||
EOQualifier *searchQualifier;
|
||||
NSArray *searchResult;
|
||||
NSDictionary *imapResult;
|
||||
// NSMutableDictionary *data;
|
||||
NGImap4Connection *connection;
|
||||
NGImap4Client *client;
|
||||
int unseen;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#import <Mailer/NSString+Mail.h>
|
||||
#import <Mailer/SOGoDraftsFolder.h>
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
#import <Mailer/SOGoMailFolder.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/SOGoSentFolder.h>
|
||||
|
@ -347,14 +348,12 @@
|
|||
BOOL asc;
|
||||
SOGoUser *activeUser;
|
||||
SOGoUserSettings *us;
|
||||
SOGoMailAccounts *clientObject;
|
||||
|
||||
sort = [self imap4SortKey];
|
||||
ascending = [[context request] formValueForKey: @"asc"];
|
||||
asc = [ascending boolValue];
|
||||
|
||||
activeUser = [context activeUser];
|
||||
clientObject = [self clientObject];
|
||||
module = @"Mail";
|
||||
us = [activeUser userSettings];
|
||||
moduleSettings = [us objectForKey: module];
|
||||
|
@ -630,6 +629,8 @@
|
|||
NSDictionary *data;
|
||||
NSRange r;
|
||||
int count;
|
||||
SOGoMailAccount *account;
|
||||
id quota;
|
||||
|
||||
uids = [self getSortedUIDsInFolder: mailFolder]; // retrieves the form parameters "sort" and "asc"
|
||||
|
||||
|
@ -649,9 +650,14 @@
|
|||
sortByThread = NO;
|
||||
}
|
||||
|
||||
// We also return the inbox quota
|
||||
account = [mailFolder mailAccountFolder];
|
||||
quota = [account getInboxQuota];
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys: uids, @"uids",
|
||||
headers, @"headers",
|
||||
[NSNumber numberWithBool: sortByThread], @"threaded", nil];
|
||||
[NSNumber numberWithBool: sortByThread], @"threaded",
|
||||
quota, @"quotas", nil];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -663,7 +669,9 @@
|
|||
NSDictionary *data;
|
||||
NSArray *uids, *threadedUids;
|
||||
NSString *noHeaders;
|
||||
SOGoMailAccount *account;
|
||||
SOGoMailFolder *folder;
|
||||
id quota;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
|
||||
|
@ -672,9 +680,11 @@
|
|||
[response setHeader: @"text/plain; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
folder = [self clientObject];
|
||||
|
||||
// TODO: we might want to flush the caches?
|
||||
//[folder flushMailCaches];
|
||||
[folder expungeLastMarkedFolder];
|
||||
|
||||
noHeaders = [request formValueForKey: @"no_headers"];
|
||||
if ([noHeaders length])
|
||||
{
|
||||
|
@ -687,8 +697,14 @@
|
|||
else
|
||||
sortByThread = NO;
|
||||
}
|
||||
|
||||
// We also return the inbox quota
|
||||
account = [folder mailAccountFolder];
|
||||
quota = [account getInboxQuota];
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys: uids, @"uids",
|
||||
[NSNumber numberWithBool: sortByThread], @"threaded", nil];
|
||||
[NSNumber numberWithBool: sortByThread], @"threaded",
|
||||
quota, @"quotas", nil];
|
||||
}
|
||||
else
|
||||
data = [self getUIDsAndHeadersInFolder: folder];
|
||||
|
|
|
@ -162,14 +162,12 @@
|
|||
SOGoMailAccount *account;
|
||||
SOGoMailFolder *inbox;
|
||||
NSDictionary *data;
|
||||
SOGoUser *activeUser;
|
||||
UIxMailListActions *actions;
|
||||
|
||||
[self _setupContext];
|
||||
|
||||
#warning this code is dirty: we should not invoke UIxMailListActions from here!
|
||||
actions = [[[UIxMailListActions new] initWithRequest: [context request]] autorelease];
|
||||
activeUser = [context activeUser];
|
||||
accounts = [self clientObject];
|
||||
|
||||
account = [accounts lookupName: @"0" inContext: context acquire: NO];
|
||||
|
@ -472,13 +470,6 @@
|
|||
|
||||
tmpKeys = [NSArray arrayWithObjects: @"headerClass", @"headerId", @"value",
|
||||
nil];
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageSubjectColumn tbtv_headercell sortableTableHeader resizable",
|
||||
@"subjectHeader", @"Subject", nil];
|
||||
[columnsMetaData setObject: [NSDictionary dictionaryWithObjects: tmpColumns
|
||||
forKeys: tmpKeys]
|
||||
forKey: @"Subject"];
|
||||
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageThreadColumn tbtv_headercell",
|
||||
@"invisibleHeader", @"Thread", nil];
|
||||
|
@ -486,6 +477,13 @@
|
|||
forKeys: tmpKeys]
|
||||
forKey: @"Thread"];
|
||||
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageSubjectColumn tbtv_headercell sortableTableHeader resizable",
|
||||
@"subjectHeader", @"Subject", nil];
|
||||
[columnsMetaData setObject: [NSDictionary dictionaryWithObjects: tmpColumns
|
||||
forKeys: tmpKeys]
|
||||
forKey: @"Subject"];
|
||||
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageFlagColumn tbtv_headercell",
|
||||
@"invisibleHeader", @"Flagged", nil];
|
||||
|
@ -582,7 +580,6 @@
|
|||
if (i == NSNotFound)
|
||||
[finalOrder insertObject: @"Thread" atIndex: 0];
|
||||
}
|
||||
|
||||
if ([self showToAddress])
|
||||
{
|
||||
i = [finalOrder indexOfObject: @"From"];
|
||||
|
|
|
@ -315,8 +315,8 @@ function mailListToggleMessagesFlagged(row) {
|
|||
}
|
||||
}
|
||||
if (selectedRowsId.length > 0) {
|
||||
var firstTd = row.childElements().first();
|
||||
var img = firstTd.childElements().first();
|
||||
var td = row.down("td.messageFlagColumn");
|
||||
var img = td.childElements().first();
|
||||
|
||||
var action = "markMessageFlagged";
|
||||
var flagged = true;
|
||||
|
@ -476,17 +476,18 @@ function deleteSelectedMessages(sender) {
|
|||
var nextUid = nextRow.id.substr(4);
|
||||
var nextIndex = Mailer.dataTable.dataSource.indexOf(nextUid);
|
||||
Mailer.dataTable.dataSource.uids[nextIndex][2] = 1; // mark it as "first"
|
||||
Mailer.dataTable.invalidate(nextUid, true);
|
||||
Mailer.dataTable.dataSource.invalidate(nextUid); // next refresh will reload headers for row
|
||||
}
|
||||
if (nextRow.id.startsWith('row_')) {
|
||||
Mailer.currentMessages[Mailer.currentMailbox] = nextRow.id.substr(4);
|
||||
nextRow.selectElement();
|
||||
if (loadMessage(Mailer.currentMessages[Mailer.currentMailbox]) && !refreshFolder)
|
||||
if (loadMessage(Mailer.currentMessages[Mailer.currentMailbox]) && !refreshFolder) {
|
||||
// Seen state has changed
|
||||
Mailer.dataTable.invalidate(Mailer.currentMessages[Mailer.currentMailbox], true);
|
||||
Mailer.dataTable.dataSource.invalidate(Mailer.currentMessages[Mailer.currentMailbox]);
|
||||
refreshFolder = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
messageContent.innerHTML = '';
|
||||
}
|
||||
|
@ -496,6 +497,7 @@ function deleteSelectedMessages(sender) {
|
|||
lastClickedRow = nextRow.rowIndex;
|
||||
lastClickedRowId = nextRow.id;
|
||||
}
|
||||
if (Mailer.currentMailboxType != "trash")
|
||||
deleteCachedMailboxByType("trash");
|
||||
}
|
||||
else {
|
||||
|
@ -522,8 +524,11 @@ function deleteSelectedMessages(sender) {
|
|||
}
|
||||
|
||||
function deleteSelectedMessagesCallback(http) {
|
||||
if (isHttpStatus204(http.status)) {
|
||||
if (http.status == 200) {
|
||||
var data = http.callbackData;
|
||||
var rdata = http.responseText.evalJSON(true);
|
||||
if (rdata.quotas && data["mailbox"].startsWith('/0/'))
|
||||
updateQuotas(rdata.quotas);
|
||||
if (data["refreshUnseenCount"])
|
||||
// TODO : the unseen count should be returned when calling the batchDelete remote action,
|
||||
// in order to avoid this extra AJAX call.
|
||||
|
@ -539,7 +544,8 @@ function deleteSelectedMessagesCallback(http) {
|
|||
}
|
||||
else {
|
||||
var html = new Element('div').update(http.responseText);
|
||||
log ("Messages deletion failed (" + http.status + ") : " + html.down('p').innerHTML);
|
||||
log ("Messages deletion failed (" + http.status + ") : ");
|
||||
log (html.down('p').innerHTML);
|
||||
showAlertDialog(_("Operation failed"));
|
||||
refreshCurrentFolder();
|
||||
}
|
||||
|
@ -1637,7 +1643,7 @@ function loadMessageCallback(http) {
|
|||
// Warning: If the user can't set the read/unread flag, it won't
|
||||
// be reflected in the view unless we force the refresh.
|
||||
if (http.callbackData.seenStateHasChanged)
|
||||
Mailer.dataTable.invalidate(msguid, true);
|
||||
Mailer.dataTable.dataSource.invalidate(msguid);
|
||||
}
|
||||
var cachedMessage = new Array();
|
||||
cachedMessage['idx'] = Mailer.currentMailbox + '/' + msguid;
|
||||
|
@ -2068,7 +2074,7 @@ function updateQuotas(quotas) {
|
|||
if (quotas)
|
||||
Mailer.quotas = quotas;
|
||||
if (Mailer.quotas && parseInt(Mailer.quotas.maxQuota) > 0) {
|
||||
log ("updating quotas");
|
||||
log ("updating quotas " + Mailer.quotas.usedSpace + "/" + Mailer.quotas.maxQuota);
|
||||
var treeContent = $("folderTreeContent");
|
||||
var tree = $("mailboxTree");
|
||||
var quotaDiv = $("quotaIndicator");
|
||||
|
|
|
@ -292,6 +292,7 @@ var SOGoDataTableInterface = {
|
|||
invalidate: function(uid, withoutRefresh) {
|
||||
// Refetch the data for uid. Only refresh the data table if
|
||||
// necessary.
|
||||
// log ("DataTable.invalidate(" + uid + ", with" + (withoutRefresh?"out":"") + " refresh)");
|
||||
var index = this.dataSource.invalidate(uid);
|
||||
this.currentRenderID = index + "-" + 1;
|
||||
this.dataSource.getData(this.currentRenderID,
|
||||
|
|
|
@ -35,6 +35,7 @@ SOGoMailDataSource = Class.create({
|
|||
},
|
||||
|
||||
remove: function(uid) {
|
||||
// log ("MailDataSource.remove(" + uid + ")");
|
||||
var index = this.invalidate(uid);
|
||||
if (index >= 0) {
|
||||
this.uids.splice(index, 1);
|
||||
|
@ -43,7 +44,7 @@ SOGoMailDataSource = Class.create({
|
|||
return index;
|
||||
},
|
||||
|
||||
init: function(uids, threaded, headers) {
|
||||
init: function(uids, threaded, headers, quotas) {
|
||||
this.uids = uids;
|
||||
if (typeof threaded != "undefined") {
|
||||
this.threaded = threaded;
|
||||
|
@ -52,6 +53,9 @@ SOGoMailDataSource = Class.create({
|
|||
}
|
||||
// log ("MailDataSource.init() " + this.uids.length + " uids loaded");
|
||||
|
||||
if (quotas && Object.isFunction(updateQuotas))
|
||||
updateQuotas(quotas);
|
||||
|
||||
if (headers) {
|
||||
var keys = headers[0];
|
||||
for (var i = 1; i < headers.length; i++) {
|
||||
|
@ -89,7 +93,7 @@ SOGoMailDataSource = Class.create({
|
|||
if (http.responseText.length > 0) {
|
||||
var data = http.responseText.evalJSON(true);
|
||||
if (data.uids)
|
||||
this.init(data.uids, data.threaded, data.headers);
|
||||
this.init(data.uids, data.threaded, data.headers, data.quotas);
|
||||
else
|
||||
this.init(data);
|
||||
if (this.delayedGetData) {
|
||||
|
@ -146,6 +150,7 @@ SOGoMailDataSource = Class.create({
|
|||
for (i = 0, j = start; j < end; j++) {
|
||||
var uid = this.threaded? this.uids[j][0] : this.uids[j];
|
||||
if (!this.cache.get(uid)) {
|
||||
// log ("MailDataSource._getData missing headers of uid " + uid + " at index " + j + (this.threaded? " (":" (non-") + "threaded)");
|
||||
missingUids[i] = uid;
|
||||
i++;
|
||||
}
|
||||
|
@ -168,9 +173,9 @@ SOGoMailDataSource = Class.create({
|
|||
if (this.ajaxGetData) {
|
||||
this.ajaxGetData.aborted = true;
|
||||
this.ajaxGetData.abort();
|
||||
// log ("MailDataSource._getData() aborted previous AJAX request");
|
||||
// log ("MailDataSource._getRemoteData() aborted previous AJAX request");
|
||||
}
|
||||
// log ("MailDataSource._getData() fetching headers of " + urlParams);
|
||||
// log ("MailDataSource._getRemoteData() fetching headers of " + urlParams);
|
||||
this.ajaxGetData = triggerAjaxRequest(this.url + "/headers",
|
||||
this._getRemoteDataCallback.bind(this),
|
||||
callbackData,
|
||||
|
@ -211,7 +216,7 @@ SOGoMailDataSource = Class.create({
|
|||
// Add thread-related data
|
||||
if (parseInt(this.uids[i][2]) > 0)
|
||||
data[j]['Thread'] = ' '; //'<img class="messageThread" src="' + ResourcesURL + '/arrow-down.png">';
|
||||
else
|
||||
else if (data[j]['Thread'])
|
||||
delete data[j]['Thread'];
|
||||
if (parseInt(this.uids[i][1]) > -1)
|
||||
data[j]['ThreadLevel'] = this.uids[i][1];
|
||||
|
|
Loading…
Reference in New Issue