merge of '6233812eac33115667675d01081adb1fed7344fd'

and 'aca422868e377bcf123be4fcaa0a258238b473a6'

Monotone-Parent: 6233812eac33115667675d01081adb1fed7344fd
Monotone-Parent: aca422868e377bcf123be4fcaa0a258238b473a6
Monotone-Revision: c4d172fda57e0bd72cb109b117dbc93d996684f0

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-12-17T20:46:13
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2007-12-17 20:46:13 +00:00
12 changed files with 245 additions and 172 deletions

View File

@@ -1,13 +1,40 @@
2007-12-17 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/MailerUI/UIxMailEditor.m ([UIxMailEditor -attachmentNames]):
initialize "attachmentNames" if it was NOT initialized... I think
this was a typo.
* SoObjects/Mailer/SOGoDraftObject.m ([SOGoDraftObject
-fetchMailForForwarding:sourceMail]): append the signature to
mails forwarded as attachment.
* UI/MailPartViewers/UIxMailPartViewer.m ([UIxMailPartViewer
-clientPart]): new method that returns the corresponding
SOGoMailPart instance.
([UIxMailPartViewer -pathToAttachment]): simplified method, ensure
the filename is present. If the part has none, create one with the
"Untitled-" prefix. Add an extension if none is found.
* UI/MailPartViewers/UIxMailPartImageViewer.m
([UIxMailPartImageViewer -pathToImage]): removed method since it
implementents exactly the same functionality as
[UIxMailPartViewer -pathToAttachment].
* SoObjects/Mailer/SOGoMailBodyPart.m ([SOGoMailBodyPart
-filename]): new method that returns the filename to the current
part by taking the different mime implementations into account.
[SOGoMailBodyPart -isBodyPartKey:inContext:]: commented out method
because we need to handle the part recognition in a different way,
by using the prefix "part" for example. One day we will do that.
* UI/Scheduler/NSArray+Scheduler.m ([NSMutableArray
-reverseArray]): new category method.
2007-12-17 Francis Lachapelle <flachapelle@inverse.ca>
* UI/MailerUI/UIxMailMainFrame.m ([UIxMailMainFrame
-composeAction]): fixed URL when no recipient is specified.
2007-12-17 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Scheduler/NSArray+Scheduler.m ([NSMutableArray
-reverseArray]): new category method.
2007-12-14 Ludovic Marcotte <ludovic@inverse.ca>
* SoObjects/Appointments/SOGoCalendarComponent.m

View File

@@ -1,47 +1,3 @@
Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m
===================================================================
--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (révision 1557)
+++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (copie de travail)
@@ -713,6 +713,39 @@
return ms;
}
+/* GCSEOAdaptorChannel protocol */
+static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \
+ @" c_name VARCHAR (256) NOT NULL,\n"
+ @" c_content VARCHAR (100000) NOT NULL,\n"
+ @" c_creationdate INT4 NOT NULL,\n"
+ @" c_lastmodified INT4 NOT NULL,\n"
+ @" c_version INT4 NOT NULL,\n"
+ @" c_deleted INT4 NULL\n"
+ @")");
+static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \
+ @" c_uid VARCHAR (256) NOT NULL,\n"
+ @" c_object VARCHAR (256) NOT NULL,\n"
+ @" c_role VARCHAR (80) NOT NULL\n"
+ @")");
+
+- (NSException *) createGCSFolderTableWithName: (NSString *) tableName
+{
+ NSString *sql;
+
+ sql = [NSString stringWithFormat: sqlFolderFormat, tableName];
+
+ return [self evaluateExpressionX: sql];
+}
+
+- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName
+{
+ NSString *sql;
+
+ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName];
+
+ return [self evaluateExpressionX: sql];
+}
+
@end /* PostgreSQL72Channel */
@implementation PostgreSQL72Channel(PrimaryKeyGeneration)
Index: sope-mime/NGImap4/NGImap4Connection.m
===================================================================
--- sope-mime/NGImap4/NGImap4Connection.m (révision 1557)
@@ -153,7 +109,14 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
return address;
}
@@ -1627,6 +1650,29 @@
@@ -1620,13 +1643,35 @@
return str;
}
-
static NSString *_parseBodyString(NGImap4ResponseParser *self,
BOOL _convertString)
{
return _parseBodyDecodeString(self, _convertString, NO /* no decode */);
}
@@ -183,7 +146,16 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self)
{
NSMutableDictionary *list;
@@ -1734,10 +1780,11 @@
@@ -1646,7 +1691,7 @@
_consumeIfMatch(self, ' ');
value = _parseBodyDecodeString(self, YES, YES);
- [list setObject:value forKey:[key lowercaseString]];
+ if (value) [list setObject:value forKey:[key lowercaseString]];
}
_consumeIfMatch(self, ')');
}
@@ -1734,10 +1779,11 @@
*encoding, *bodysize;
NSDictionary *parameterList;
NSMutableDictionary *dict;
@@ -196,7 +168,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
_consumeIfMatch(self, ' ');
parameterList = _parseBodyParameterList(self);
_consumeIfMatch(self, ' ');
@@ -1762,7 +1809,8 @@
@@ -1762,7 +1808,8 @@
_consumeIfMatch(self, ' ');
[dict setObject:_parseBodyString(self, YES) forKey:@"lines"];
}
@@ -206,7 +178,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_la(self, 0) != ')') {
_consumeIfMatch(self, ' ');
_consumeIfMatch(self, '(');
@@ -1805,14 +1853,9 @@
@@ -1805,14 +1852,9 @@
forKey: @"disposition"];
if (_la(self, 0) != ')') {
_consume(self,1);
@@ -224,7 +196,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_la(self, 0) != ')') {
_consume(self,1);
[dict setObject: _parseBodyString(self, YES)
@@ -1829,6 +1872,7 @@
@@ -1829,6 +1871,7 @@
static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self,
BOOL isBodyStructure) {
NSMutableArray *parts;
@@ -232,7 +204,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
NSString *kind;
NSMutableDictionary *dict;
@@ -1854,14 +1898,9 @@
@@ -1854,14 +1897,9 @@
forKey: @"disposition"];
if (_la(self, 0) != ')') {
_consume(self,1);
@@ -250,7 +222,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_la(self, 0) != ')') {
_consume(self,1);
[dict setObject: _parseBodyString(self, YES)
@@ -2170,6 +2209,21 @@
@@ -2170,6 +2208,21 @@
}
}
@@ -1155,6 +1127,50 @@ Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m
}
return data;
}
Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m
===================================================================
--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (révision 1557)
+++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (copie de travail)
@@ -713,6 +713,39 @@
return ms;
}
+/* GCSEOAdaptorChannel protocol */
+static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \
+ @" c_name VARCHAR (256) NOT NULL,\n"
+ @" c_content VARCHAR (100000) NOT NULL,\n"
+ @" c_creationdate INT4 NOT NULL,\n"
+ @" c_lastmodified INT4 NOT NULL,\n"
+ @" c_version INT4 NOT NULL,\n"
+ @" c_deleted INT4 NULL\n"
+ @")");
+static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \
+ @" c_uid VARCHAR (256) NOT NULL,\n"
+ @" c_object VARCHAR (256) NOT NULL,\n"
+ @" c_role VARCHAR (80) NOT NULL\n"
+ @")");
+
+- (NSException *) createGCSFolderTableWithName: (NSString *) tableName
+{
+ NSString *sql;
+
+ sql = [NSString stringWithFormat: sqlFolderFormat, tableName];
+
+ return [self evaluateExpressionX: sql];
+}
+
+- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName
+{
+ NSString *sql;
+
+ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName];
+
+ return [self evaluateExpressionX: sql];
+}
+
@end /* PostgreSQL72Channel */
@implementation PostgreSQL72Channel(PrimaryKeyGeneration)
Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m
===================================================================
--- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (révision 1557)
@@ -1515,6 +1531,27 @@ Index: sope-appserver/NGObjWeb/WOContext.m
if ((serverURL = [rq headerForKey:@"x-webobjects-server-url"]) == nil) {
if ((host = [rq headerForKey:@"host"]))
serverURL = [@"http://" stringByAppendingString:host];
Index: sope-appserver/NGObjWeb/DAVPropMap.plist
===================================================================
--- sope-appserver/NGObjWeb/DAVPropMap.plist (révision 1557)
+++ sope-appserver/NGObjWeb/DAVPropMap.plist (copie de travail)
@@ -123,11 +123,14 @@
/* CalDAV */
"{urn:ietf:params:xml:ns:caldav}calendar-home-set" = davCalendarHomeSet;
+ "{urn:ietf:params:xml:ns:caldav}calendar-user-address-set" = davCalendarUserAddressSet;
+ "{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL" = davCalendarScheduleInboxURL;
+ "{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL" = davCalendarScheduleOutboxURL;
/* Apple CalServer */
- "{http://apple.com/ns/calendarserver/}dropbox-home-URL" =
+ "{http://calendarserver.org/ns/}dropbox-home-URL" =
davDropboxHomeURL;
- "{http://apple.com/ns/calendarserver/}notifications-URL" =
+ "{http://calendarserver.org/ns/}notifications-URL" =
davNotificationsURL;
"{com.apple.ical:}calendarcolor" = davCalendarColor;
}
Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m
===================================================================
--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (révision 1557)

View File

@@ -1,5 +1,5 @@
<#IsSubject>Rendez-vous du <#OldAptStartDate /> à <#OldAptStartTime /> modifié</#IsSubject>
<#IsBody>
La réunion qui devait se dérouler le <#OldAptStartDate /> à <#OldAptStartTime /> est maintenant prévue le <#NewAptStartDate /> à <#NewAptStartTime />.
Vous êtes invité à accepter ou refuser de participer à la réunion pour cette nouvelle date à l'adresse <#HomePageURL />.
Vous êtes invité à accepter ou refuser de participer à la réunion pour cette nouvelle date à l'adresse <#HomePageURL />.
</#IsBody>

View File

@@ -634,6 +634,7 @@ static BOOL showTextAttachmentsInline = NO;
{
NSDictionary *info, *attachment;
SOGoUser *currentUser;
NSString *signature;
[sourceMail fetchCoreInfos];
@@ -659,6 +660,9 @@ static BOOL showTextAttachmentsInline = NO;
{
// TODO: use subject for filename?
// error = [newDraft saveAttachment:content withName:@"forward.mail"];
signature = [currentUser signature];
if ([signature length])
[self setText: [NSString stringWithFormat: @"\n-- \n%@", signature]];
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
[sourceMail filenameForForward], @"filename",
@"message/rfc822", @"mimetype",
@@ -666,6 +670,7 @@ static BOOL showTextAttachmentsInline = NO;
[self saveAttachment: [sourceMail content]
withMetadata: attachment];
}
[self storeInfo];
}

View File

@@ -53,6 +53,7 @@
- (NSString *) bodyPartName;
- (NSArray *) bodyPartPath;
- (NSString *) bodyPartIdentifier;
- (NSString *) filename;
/* part info */

View File

@@ -73,9 +73,9 @@ static BOOL debugOn = NO;
- (void) dealloc
{
[self->partInfo release];
[self->identifier release];
[self->pathToPart release];
[partInfo release];
[identifier release];
[pathToPart release];
[super dealloc];
}
@@ -108,8 +108,8 @@ static BOOL debugOn = NO;
NSMutableArray *p;
id obj;
if (self->pathToPart != nil)
return [self->pathToPart isNotNull] ? self->pathToPart : nil;
if (pathToPart != nil)
return [pathToPart isNotNull] ? pathToPart : nil;
p = [[NSMutableArray alloc] initWithCapacity:8];
for (obj = self; [obj isKindOfClass:[SOGoMailBodyPart class]];
@@ -117,18 +117,18 @@ static BOOL debugOn = NO;
[p insertObject:[obj bodyPartName] atIndex:0];
}
self->pathToPart = [p copy];
pathToPart = [p copy];
[p release];
return self->pathToPart;
return pathToPart;
}
- (NSString *)bodyPartIdentifier {
if (self->identifier != nil)
return [self->identifier isNotNull] ? self->identifier : nil;
if (identifier != nil)
return [identifier isNotNull] ? identifier : nil;
self->identifier =
identifier =
[[[self bodyPartPath] componentsJoinedByString:@"."] copy];
return self->identifier;
return identifier;
}
- (NSURL *)imap4URL {
@@ -139,12 +139,12 @@ static BOOL debugOn = NO;
/* part info */
- (id)partInfo {
if (self->partInfo != nil)
return [self->partInfo isNotNull] ? self->partInfo : nil;
if (partInfo != nil)
return [partInfo isNotNull] ? partInfo : nil;
self->partInfo =
partInfo =
[[[self mailObject] lookupInfoForBodyPart:[self bodyPartPath]] retain];
return self->partInfo;
return partInfo;
}
/* name lookup */
@@ -160,25 +160,40 @@ static BOOL debugOn = NO;
return [clazz objectWithName: _key inContainer: self];
}
- (NSString *) filename
{
NSString *filename;
NSDictionary *parameters;
[self partInfo];
filename = [[partInfo objectForKey: @"parameterList"]
objectForKey: @"name"];
if (!filename)
{
parameters = [[partInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
filename = [parameters objectForKey: @"filename"];
}
return filename;
}
/* We overwrite the super's class method in order to make sure
we aren't dealing with our actual filename as the _key. That
could lead to problems if we weren't doing this as our filename
could start with a digit, leading to a wrong assumption in
the super class
*/
- (BOOL)isBodyPartKey:(NSString *)_key inContext:(id)_ctx
{
NSString *s;
s = [[[self partInfo] objectForKey: @"parameterList"] objectForKey: @"name"];
// - (BOOL)isBodyPartKey:(NSString *)_key inContext:(id)_ctx
// {
// NSString *s;
if (!s)
s = [[[[self partInfo] objectForKey: @"disposition"] objectForKey: @"parameterList"] objectForKey: @"filename"];
if (s && [s isEqualToString: _key]) return NO;
// s = [self filename];
// if (s && [s isEqualToString: _key]) return NO;
return [super isBodyPartKey: _key inContext: _ctx];
}
// return [super isBodyPartKey: _key inContext: _ctx];
// }
- (id) lookupName: (NSString *) _key
inContext: (id) _ctx
@@ -355,16 +370,13 @@ static BOOL debugOn = NO;
[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 (asAttachment)
{
fileName = [self filename];
if ([fileName length])
[r setHeader: [NSString stringWithFormat: @"attachment; filename=%@", fileName]
forKey: @"content-disposition"];
}
if ((etag = [self davEntityTag]) != nil)
[r setHeader:etag forKey:@"etag"];

View File

@@ -19,6 +19,8 @@
02111-1307, USA.
*/
#import <SoObjects/Mailer/SOGoMailBodyPart.h>
#import "UIxMailPartViewer.h"
@interface UIxMailPartImageViewer : UIxMailPartViewer
@@ -29,26 +31,4 @@
@implementation UIxMailPartImageViewer
/* URLs */
- (NSString *) pathToImage
{
NSMutableString *url;
NSString *s;
s = [[self clientObject] baseURLInContext: [self context]];
url = [NSMutableString stringWithString: s];
if (![url hasSuffix: @"/"])
[url appendString: @"/"];
s = [[self partPath] componentsJoinedByString:@"/"];
[url appendString: s];
s = [self preferredPathExtension];
if (s)
[url appendFormat: @".%@", s];
return url;
}
@end /* UIxMailPartImageViewer */

View File

@@ -41,7 +41,11 @@
content.
*/
@class NSData, NSArray, NSFormatter;
@class NSArray;
@class NSData;
@class NSFormatter;
@class SOGoMailBodyPart;
@interface UIxMailPartViewer : UIxComponent
{
@@ -58,6 +62,8 @@
- (void)setBodyInfo:(id)_info;
- (id)bodyInfo;
- (SOGoMailBodyPart *) clientPart;
- (NSData *)flatContent;
- (NSData *)decodedFlatContent;
- (NSString *)flatContentAsString;

View File

@@ -134,29 +134,25 @@
return [self flatContent];
}
- (NSData *) content
- (SOGoMailBodyPart *) clientPart
{
NSData *content;
NSEnumerator *parts;
id currentObject;
NSString *currentPart;
content = nil;
NSEnumerator *parts;
currentObject = [self clientObject];
parts = [partPath objectEnumerator];
currentPart = [parts nextObject];
while (currentPart)
{
currentObject = [currentObject lookupName: currentPart
inContext: context
acquire: NO];
currentPart = [parts nextObject];
}
while ((currentPart = [parts nextObject]))
currentObject = [currentObject lookupName: currentPart
inContext: context
acquire: NO];
content = [currentObject fetchBLOB];
return currentObject;
}
return content;
- (NSData *) content
{
return [[self clientPart] fetchBLOB];
}
- (NSString *) flatContentAsString
@@ -323,32 +319,41 @@
return url;
}
- (NSString *) _filenameForAttachment: (SOGoMailBodyPart *) bodyPart
{
NSMutableString *filename;
NSString *extension;
filename = [NSMutableString stringWithString: [bodyPart filename]];
if (![filename length])
[filename appendFormat: @"%@-%@",
[self labelForKey: @"Untitled"],
[bodyPart nameInContainer]];
if (![[filename pathExtension] length])
{
extension = [self preferredPathExtension];
if (extension)
[filename appendFormat: @".%@", extension];
}
return [filename stringByEscapingURL];
}
- (NSString *) pathToAttachment
{
/* this generates a more beautiful 'download' URL for a part */
NSString *fn;
NSMutableString *url;
NSString *s;
SOGoMailBodyPart *bodyPart;
fn = [self filename];
if ([fn length] > 0)
{
/* get basic URL */
url = [NSMutableString stringWithString: [self pathToAttachmentObject]];
/*
If we have an attachment name, we attach it, this is properly handled by
SOGoMailBodyPart.
*/
if (![url hasSuffix: @"/"])
[url appendString: @"/"];
if (isdigit([url characterAtIndex: 0]))
[url appendString: @"fn-"];
[url appendString: [fn stringByEscapingURL]];
// TODO: should we check for a proper extension?
}
else
url = nil;
bodyPart = [self clientPart];
s = [bodyPart baseURLInContext: [self context]];
url = [NSMutableString stringWithString: s];
if (![url hasSuffix: @"/"])
[url appendString: @"/"];
// s = [[self partPath] componentsJoinedByString: @"/"];
[url appendString: [self _filenameForAttachment: bodyPart]];
return url;
}

View File

@@ -396,11 +396,11 @@ static NSArray *infoKeys = nil;
{
NSArray *a;
if (attachmentNames)
if (!attachmentNames)
{
a = [[self clientObject] fetchAttachmentNames];
a = [a sortedArrayUsingSelector: @selector (compare:)];
attachmentNames = [a copy];
ASSIGN (attachmentNames,
[a sortedArrayUsingSelector: @selector (compare:)]);
}
return attachmentNames;

View File

@@ -3,7 +3,7 @@
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
var:src="pathToImage"
var:src="pathToAttachment"
var:title="filenameForDisplay"
class="mailer_imagecontent"
></img>

View File

@@ -23,15 +23,15 @@
</div>
<form const:href="send" name="pageform" enctype="multipart/form-data">
<div id="attachmentsArea">
<var:string label:value="Attachments:" />
<ul id="attachments">
<var:foreach list="attachmentNames" item="attachmentName"
><li><img rsrc:src="attachment.gif"
/><var:string value="attachmentName"
/></li></var:foreach>
</ul>
</div>
<div id="attachmentsArea">
<var:string label:value="Attachments:" />
<ul id="attachments">
<var:foreach list="attachmentNames" item="attachmentName"
><li><img rsrc:src="attachment.gif"
/><var:string value="attachmentName"
/></li></var:foreach>
</ul>
</div>
<div id="headerArea">
<span class="headerField"><var:string label:value="From" />:</span>
<var:popup const:name="from"
@@ -47,12 +47,12 @@
><span class="headerField"><var:string label:value="Subject"
/>:</span
>
<input name="subject"
type="text"
class="textField"
var:value="subject"
/></div>
<!-- separator line --><hr/>
<input name="subject"
type="text"
class="textField"
var:value="subject"
/></div>
<!-- separator line --><hr/>
</div>
<textarea id="text" name="text" rows="30" var:value="text"/>
<!-- img rsrc:src="tbird_073_compose.png" alt="screenshot" / -->