+2007-12-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject
+ -davCreationDate])
+ ([SOGoContentObject -davLastModified])
+ ([SOGoContentObject -davContentLength]): implemented dav methods.
+
+2007-12-10 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * SoObjects/Mailer/SOGoMailBodyPart.m ([SOGoMailBodyPart
+ -GETAction:]): when asAttachment is set to true, the header
+ "content-disposition" is set to "attachment" so browsers like IE
+ and Safari properly asks the user to save the file.
+
+2007-12-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * UI/MailPartViewers/UIxMailPartHTMLViewer.m
+ ([UIxMailPartHTMLViewer -flatContentAsString]): when in
+ UIxMailPartAlternative, scan the filenames of potential cid at the
+ same level as our parent.
+
2007-12-07 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Main/SOGo.m ([SOGo -run]): the table creation script now have a
+2007-12-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * GCSFolder.m ([GCSFolder -creationDateOfEntryWithName:]): new
+ method that returns the creation date of the specified entry.
+ ([GCSFolder -lastModificationOfEntryWithName:]): same as above for
+ the last modification time.
+
2007-11-27 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* GCSFolder.m ([GCSFolder -versionOfContentWithName:], [GCSFolder
- (NSArray *)allSubFolderNames;
- (NSNumber *)versionOfContentWithName:(NSString *)_name;
+- (NSCalendarDate *)creationDateOfEntryWithName:(NSString *)_name;
+- (NSCalendarDate *)lastModificationOfEntryWithName:(NSString *)_name;
- (NSString *)fetchContentWithName:(NSString *)_name;
- (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name
ignoreDeleted: YES];
}
+- (NSCalendarDate *)creationDateOfEntryWithName:(NSString *)_name {
+ int seconds;
+
+ seconds = [[self _fetchValueOfColumn:@"c_creationdate" inContentWithName:_name
+ ignoreDeleted: YES] intValue];
+
+ return [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
+}
+
+- (NSCalendarDate *)lastModificationOfEntryWithName:(NSString *)_name {
+ int seconds;
+
+ seconds = [[self _fetchValueOfColumn:@"c_lastmodified" inContentWithName:_name
+ ignoreDeleted: YES] intValue];
+
+ return [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
+}
+
- (NSNumber *)deletionOfContentWithName:(NSString *)_name {
return [self _fetchValueOfColumn:@"c_deleted" inContentWithName:_name
ignoreDeleted: NO];
+2007-12-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * iCalTimeZone.m ([iCalTimeZone -periodForDate:date]): at least
+ one timezone period is needed so we might need to fallback on the
+ only one present if the other does not exist.
+
2007-11-29 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* iCalDateTime.m ([iCalDateTime -timeZone]): log a message if the
forDate: date];
standardOccurence = [self _occurenceForPeriodNamed: @"standard"
forDate: date];
- if ([date earlierDate: daylightOccurence] == date
- || [date earlierDate: standardOccurence] == standardOccurence)
+
+ if (!standardOccurence)
+ period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"daylight"];
+ else if (!daylightOccurence)
+ period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"standard"];
+ else if ([date earlierDate: daylightOccurence] == date
+ || [date earlierDate: standardOccurence] == standardOccurence)
period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"standard"];
else
period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"daylight"];
- NSLog (@"chosen period: '%@'", [period tag]);
+// NSLog (@"chosen period: '%@'", [period tag]);
return period;
}
NSArray *pathToPart;
NSString *identifier;
id partInfo;
+ BOOL asAttachment;
}
/* hierarchy */
- (id) partInfo;
- (NSData *) fetchBLOB;
+- (void) setAsAttachment;
+- (BOOL) asAttachment;
/* factory */
NSLog(@"Note(SOGoMailBodyPart): etag caching disabled!");
}
-- (void)dealloc {
+- (id) init
+{
+ if ((self = [super init]))
+ asAttachment = NO;
+
+ return self;
+}
+
+- (void) dealloc
+{
[self->partInfo release];
[self->identifier release];
[self->pathToPart release];
[super dealloc];
}
+- (void) setAsAttachment
+{
+ asAttachment = YES;
+}
+
+
/* hierarchy */
- (SOGoMailObject *)mailObject {
/* lookup body part */
if ([self isBodyPartKey:_key inContext:_ctx])
obj = [self lookupImap4BodyPartKey:_key inContext:_ctx];
+ else if ([_key isEqualToString: @"asAttachment"])
+ [self setAsAttachment];
/* should check whether such a filename exist in the attached names */
if (!obj)
obj = self;
/* try type from body structure info */
- parts = [self contentTypeForBodyPartInfo: [self partInfo]];
- contentType = [[parts componentsSeparatedByString: @";"] objectAtIndex: 0];
-
- if (![contentType length])
- {
- extension = [[self nameInContainer] pathExtension];
- contentType = [self contentTypeForPathExtension: extension];
- }
+ if (asAttachment)
+ contentType = @"application/octet-stream";
+ else {
+ parts = [self contentTypeForBodyPartInfo: [self partInfo]];
+ contentType = [[parts componentsSeparatedByString: @";"] objectAtIndex: 0];
+
+ if (![contentType length])
+ {
+ extension = [[self nameInContainer] pathExtension];
+ contentType = [self contentTypeForPathExtension: extension];
+ }
+ }
return contentType;
}
NSException *error;
WOResponse *r;
NSData *data;
- NSString *etag, *mimeType;
+ NSString *etag, *mimeType, *fileName;
if ((error = [self matchesRequestConditionInContext:_ctx]) != nil) {
// TODO: currently we fetch the body structure to get here - check this!
[r setHeader: mimeType forKey:@"content-type"];
[r setHeader: [NSString stringWithFormat:@"%d", [data length]]
forKey: @"content-length"];
+
+ if (asAttachment) {
+ fileName = [[[self partInfo] objectForKey: @"parameterList"] objectForKey: @"name"];
+ if (!fileName)
+ fileName = [[[[self partInfo] objectForKey: @"disposition"]
+ objectForKey: @"parameterList"]
+ objectForKey: @"filename"];
+ if ([fileName length])
+ [r setHeader: [NSString stringWithFormat: @"attachment; filename=%@", fileName]
+ forKey: @"content-disposition"];
+ }
if ((etag = [self davEntityTag]) != nil)
[r setHeader:etag forKey:@"etag"];
#import <NGExtensions/NSObject+Logs.h>
#import <GDLContentStore/GCSFolder.h>
+#import "NSCalendarDate+SOGo.h"
#import "SOGoGCSFolder.h"
#import "SOGoUser.h"
#import "SOGoPermissions.h"
}
/* WebDAV */
+- (NSString *) davCreationDate
+{
+ NSCalendarDate *date;
+
+ date = [[self ocsFolder] creationDateOfEntryWithName: nameInContainer];
+
+ return [date rfc822DateString];
+}
+
+- (NSString *) davLastModified
+{
+ NSCalendarDate *date;
+
+ date = [[self ocsFolder] lastModificationOfEntryWithName: nameInContainer];
+
+ return [date rfc822DateString];
+}
+
+- (NSString *) davContentLength
+{
+ return [NSString stringWithFormat: @"%u",
+ [content
+ lengthOfBytesUsingEncoding: NSISOLatin1StringEncoding]];
+}
- (NSException *) davMoveToTargetObject: (id) _target
newName: (NSString *) _name
andBaseURL: (NSString *) url
intoDictionary: (NSMutableDictionary *) attachmentIds
{
- NSString *bodyId;
+ NSString *bodyId, *filename;
+ NSMutableString *attachmentURL;
bodyId = [part objectForKey: @"bodyId"];
if ([bodyId length] > 0)
{
+ filename = [[part objectForKey: @"parameterList"] objectForKey: @"name"];
+ if (!filename)
+ filename = [[[part objectForKey: @"disposition"]
+ objectForKey: @"parameterList"]
+ objectForKey: @"filename"];
if ([bodyId hasPrefix: @"<"])
bodyId = [bodyId substringFromIndex: 1];
if ([bodyId hasSuffix: @">"])
bodyId = [bodyId substringToIndex: [bodyId length] - 1];
- [attachmentIds setObject: [url stringByAppendingFormat: @"/%d", count]
- forKey: bodyId];
+ attachmentURL = [NSMutableString stringWithString: url];
+ [attachmentURL appendFormat: @"/%d", count];
+ if ([filename length])
+ [attachmentURL appendFormat: @"/%@", filename];
+ [attachmentIds setObject: attachmentURL forKey: bodyId];
}
}
NSMutableDictionary *attachmentIds;
UIxMailPartViewer *parent;
unsigned int count, max;
- NSMutableString *url;
+// NSMutableString *url;
NSString *baseURL;
NSArray *parts;
isEqualToString: @"UIxMailPartAlternativeViewer"])
{
baseURL = [[self clientObject] baseURLInContext: context];
- url = [NSMutableString new];
- [url appendString: baseURL];
- [url appendFormat: @"/%@", [partPath componentsJoinedByString: @"/"]];
- [url deleteCharactersInRange: NSMakeRange([url length] - 2, 2)];
- parts = [[parent bodyInfo] objectForKey: @"parts"];
+// url = [NSMutableString new];
+// [url appendString: baseURL];
+// [url appendFormat: @"/%@", [partPath componentsJoinedByString: @"/"]];
+// [url deleteCharactersInRange: NSMakeRange([url length] - 4, 4)];
+ parts = [[[parent parent] bodyInfo] objectForKey: @"parts"];
max = [parts count];
for (count = 0; count < max; count++)
[self _convertReferencesForPart: [parts objectAtIndex: count]
withCount: count + 1
- andBaseURL: url
+ andBaseURL: baseURL
intoDictionary: attachmentIds];
- [url release];
+// [url release];
}
return attachmentIds;
"Create Filter From Message..." = "Create Filter From Message...";
/* Image Popup menu */
-"View Image" = "View Image";
+"Save Image" = "Save Image";
/* Mailbox popup menus */
"Open in New Mail Window" = "Open in New Mail Window";
"Create Filter From Message..." = "Créer un filtre à partir du message...";
/* Image Popup menu */
-"View Image" = "Voir l'image";
+"Save Image" = "Enregistrer l'image";
/* Mailbox popup menus */
"Open in New Mail Window" = "Ouvrir dans une nouvelle fenétre";
"Create Filter From Message..." = "Filter aus Nachricht erstellen...";
/* Image Popup menu */
-"View Image" = "View Image";
+"Save Image" = "Save Image";
/* Mailbox popup menus */
"Open in New Mail Window" = "In neuem Fenster öffnen";
<div class="menu" id="imageMenu">
<ul>
- <li id="view_image"><var:string label:value="View Image"/></li>
+ <li id="save_image"><var:string label:value="Save Image"/></li>
</ul>
</div>
/* bulk delete of messages */
function deleteSelectedMessages(sender) {
- var messageList = $("messageList");
- var rowIds = messageList.getSelectedRowsId();
-
- if (rowIds.length > 0) {
- for (var i = 0; i < rowIds.length; i++) {
- var url;
- var rowId = rowIds[i].substr(4);
- var messageId = Mailer.currentMailbox + "/" + rowId;
- url = ApplicationBaseURL + messageId + "/trash";
- deleteMessageRequestCount++;
- var data = { "id": rowId, "mailbox": Mailer.currentMailbox, "messageId": messageId };
- triggerAjaxRequest(url, deleteSelectedMessagesCallback, data);
- }
- } else {
- window.alert(labels["Please select a message."]);
- }
-
- return false;
+ var messageList = $("messageList");
+ var rowIds = messageList.getSelectedRowsId();
+
+ if (rowIds.length > 0) {
+ for (var i = 0; i < rowIds.length; i++) {
+ var url;
+ var rowId = rowIds[i].substr(4);
+ var messageId = Mailer.currentMailbox + "/" + rowId;
+ url = ApplicationBaseURL + messageId + "/trash";
+ deleteMessageRequestCount++;
+ var data = { "id": rowId, "mailbox": Mailer.currentMailbox, "messageId": messageId };
+ triggerAjaxRequest(url, deleteSelectedMessagesCallback, data);
+ }
+ }
+ else
+ window.alert(labels["Please select a message."]);
+
+ return false;
}
function deleteSelectedMessagesCallback(http) {
deleteCachedMessage(data["messageId"]);
deleteMessageRequestCount--;
if (Mailer.currentMailbox == data["mailbox"]) {
-
var div = $('messageContent');
if (Mailer.currentMessages[Mailer.currentMailbox] == data["id"]) {
div.update();
new Ajax.Request(url, {
method: 'post',
onFailure: function(transport) {
- if (!isHttpStatus204)
- log("draftDeleteCallback: problem during ajax request: " + transport.status);
+ log("draftDeleteCallback: problem during ajax request: " + transport.status);
}
});
}
}
function onMenuDeleteMessage(event) {
- deleteSelectedMessages();
- preventDefault(event);
+ deleteSelectedMessages();
+ preventDefault(event);
+}
+
+function deleteMessage(url, id, mailbox, messageId) {
+ var data = { "id": id, "mailbox": mailbox, "messageId": messageId };
+ deleteMessageRequestCount++;
+ triggerAjaxRequest(url, deleteSelectedMessagesCallback, data);
+}
+
+function deleteMessageWithDelay(url, id, mailbox, messageId) {
+ /* this is called by UIxMailPopupView with window.opener */
+ setTimeout("deleteMessage('" +
+ url + "', '" +
+ id + "', '" +
+ mailbox + "', '" +
+ messageId + "')",
+ 50);
}
function onPrintCurrentMessage(event) {
if (mailbox != Mailer.currentMailbox || reload) {
Mailer.currentMailbox = mailbox;
var url = ApplicationBaseURL + encodeURI(mailbox) + "/view?noframe=1";
- var messageContent = $("messageContent");
- messageContent.update();
- lastClickedRow = -1; // from generic.js
-
+
+ if (!reload) {
+ var messageContent = $("messageContent");
+ messageContent.update();
+ lastClickedRow = -1; // from generic.js
+ }
+
var currentMessage;
- if (!idx) {
+ if (!idx && !reload) {
currentMessage = Mailer.currentMessages[mailbox];
if (currentMessage) {
loadMessage(currentMessage);
preventDefault(event);
}
-function viewImage(event) {
+function saveImage(event) {
var img = document.menuTarget;
- window.open(img.getAttribute("src"),'_blank','resizable=1');
+ var url = img.getAttribute("src");
+ var urlAsAttachment = url.replace(/(\/[^\/]*)$/,"/asAttachment$1");
+
+ window.location.href = urlAsAttachment;
}
/* contacts */
"mark-menu", "-",
null, null,
onMenuDeleteMessage);
- menus["imageMenu"] = new Array(viewImage);
+ menus["imageMenu"] = new Array(saveImage);
menus["messageContentMenu"] = new Array(onMenuReplyToSender,
onMenuReplyToAll,
onMenuForwardMessage,
resizeMailContent();
}
+function onMenuDeleteMessage(event) {
+
+ if (window.opener && window.opener.open && !window.opener.closed) {
+ var rowId = window.name.substr(9);
+ var messageId = window.opener.Mailer.currentMailbox + "/" + rowId;
+ var url = ApplicationBaseURL + messageId + "/trash";
+
+ window.opener.deleteMessageWithDelay(url,
+ rowId,
+ window.opener.Mailer.currentMailbox,
+ messageId);
+ }
+
+ window.close();
+ return false;
+}
+
FastInit.addOnLoad(initPopupMailer);