Add support for threaded emails (for 'conversation' view in mail clients)

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/ec/trunk@36493 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2013-04-08 15:50:32 +00:00
parent 27a4a7328c
commit f410d97aaf
5 changed files with 158 additions and 14 deletions

View file

@ -220,6 +220,13 @@
* NB. The value of the <em>Subject</em> field is used as a template
* in the same way as the <em>Replacement</em> fields.
* </p>
* <p>The <em>Threaded</em> is just like the Email array except that
* it is only used for alarm messages, and the messages sent to the
* addresses in this array form a chain of linke messages referring
* back to each other rather than all being versions of the same
* message. This may give a better effect for people using mail
* clients which don't support the message-ID header well.
* </p>
*
* <p>Configuration of the alerter is done by the 'Alerter' key in the user
* defaults system. The value for this key must be a dictionary configuring
@ -293,6 +300,7 @@
GSMimeSMTPClient *smtp; /** Client connection to MTA */
BOOL debug; /** Debug enabled in config */
BOOL supersede; /** If a clear should replace original */
BOOL eThreaded; /** alarm reminder emails threaded */
}
/** Called when user defaults are updated, this fetches the dictionary

View file

@ -344,9 +344,9 @@ replaceFields(NSDictionary *fields, NSString *template)
GSMimeDocument *doc;
doc = AUTORELEASE([GSMimeDocument new]);
[doc setHeader: @"subject" value: subject parameters: nil];
[doc setHeader: @"to" value: address parameters: nil];
[doc setHeader: @"from" value: eFrom parameters: nil];
[doc setHeader: @"Subject" value: subject parameters: nil];
[doc setHeader: @"To" value: address parameters: nil];
[doc setHeader: @"From" value: eFrom parameters: nil];
[doc setContent: text type: @"text/plain" name: nil];
[[self _smtp] send: doc];
}
@ -660,6 +660,80 @@ replaceFields(NSDictionary *fields, NSString *template)
}
NS_ENDHANDLER
NS_DURING
{
o = [d objectForKey: @"Threaded"];
if ([o isKindOfClass: [NSString class]] == YES)
{
if ([o hasPrefix: @"("])
{
o = [(NSString*)o propertyList];
}
else
{
o = [NSArray arrayWithObject: o];
}
}
if (o != nil)
{
NSString *s = [d objectForKey: @"Subject"];
if (reminder > 0)
{
NSString *emailIdentifier;
NSString *emailInReplyTo;
if (1 == reminder)
{
emailInReplyTo = identifier;
emailIdentifier
= [identifier stringByAppendingString: @"_1"];
}
else
{
emailInReplyTo
= [NSString stringWithFormat: @"%@_%d",
identifier, reminder - 1];
emailIdentifier
= [NSString stringWithFormat: @"%@_%d",
identifier, reminder];
}
[m setObject: emailIdentifier
forKey: @"EmailIdentifier"];
[m setObject: emailInReplyTo
forKey: @"EmailInReplyTo"];
}
if (s != nil)
{
[m setObject: s forKey: @"Subject"];
}
s = [d objectForKey: @"EmailReplacement"];
if (nil == s)
{
s = [d objectForKey: @"Replacement"];
if (nil == s)
{
/* Full details. */
s = @"{Server}({Host}): {Timestamp} {Type}"
@" - {Message}";
}
}
[m setObject: s forKey: @"Replacement"];
[self mail: m identifier: identifier isClear: isClear to: o];
}
}
NS_HANDLER
{
NSLog(@"Exception handling Email send for rule: %@",
localException);
}
NS_ENDHANDLER
[m removeObjectForKey: @"EmailIdentifier"];
[m removeObjectForKey: @"EmailInReplyTo"];
NS_DURING
{
o = [d objectForKey: @"Sms"];
@ -904,15 +978,71 @@ replaceFields(NSDictionary *fields, NSString *template)
[self _smtp];
doc = AUTORELEASE([GSMimeDocument new]);
[doc setHeader: @"subject" value: subject parameters: nil];
[doc setHeader: @"Subject" value: subject parameters: nil];
[doc setContent: text type: @"text/plain" name: nil];
[doc setHeader: @"from" value: eFrom parameters: nil];
[doc setHeader: @"From" value: eFrom parameters: nil];
if ([identifier length] > 0)
{
NSString *mID;
mID = [NSString stringWithFormat: @"<alrm%@@%@>", identifier, eBase];
/* This may reference an earlier email (for threaded display)
*/
mID = [m objectForKey: @"EmailInReplyTo"];
if (nil != mID)
{
mID = [NSString stringWithFormat: @"<alrm%@@%@>", mID, eBase];
[doc setHeader: @"In-Reply-To" value: mID parameters: nil];
}
/* We may have an identifier set in the dictionary to use
*/
mID = [m objectForKey: @"EmailIdentifier"];
if (nil != mID)
{
NSRange r = [mID rangeOfString: @"_"];
if (r.length > 0)
{
#if 1
int version;
/* Reference all earlier messages in thread.
*/
version = [[mID substringFromIndex: NSMaxRange(r)] intValue];
if (version > 1)
{
NSMutableString *ms = [NSMutableString string];
int index;
for (index = 1; index < version; index++)
{
if (index > 1)
{
[ms appendString: @" "];
}
[ms appendFormat: @"<alrm%@_%d@%@>",
mID, index, eBase];
}
[doc setHeader: @"References" value: ms parameters: nil];
}
#else
NSString *ref;
/* Reference the original message at start of thread.
*/
ref = [NSString stringWithFormat: @"<alrm%@@%@>",
[mID substringToIndex: r.location], eBase];
[doc setHeader: @"References" value: ref parameters: nil];
#endif
}
mID = [NSString stringWithFormat: @"<alrm%@@%@>", mID, eBase];
}
else
{
mID = [NSString stringWithFormat: @"<alrm%@@%@>",
identifier, eBase];
}
if (YES == isClear)
{
@ -933,7 +1063,7 @@ replaceFields(NSDictionary *fields, NSString *template)
[doc setHeader: @"Message-ID" value: mID parameters: nil];
}
}
else if ([identifier length] > 0)
else
{
[doc setHeader: @"Message-ID" value: mID parameters: nil];
}
@ -946,7 +1076,7 @@ replaceFields(NSDictionary *fields, NSString *template)
GSMimeDocument *msg;
msg = AUTORELEASE([doc copy]);
[msg setHeader: @"to" value: d parameters: nil];
[msg setHeader: @"To" value: d parameters: nil];
[smtp send: msg];
}
NS_HANDLER

View file

@ -426,7 +426,8 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
- (NSString*) description
{
return [NSString stringWithFormat: @"Control server\n%@\n%@", alerter, sink];
return [NSString stringWithFormat: @"%@ running since %@\n%@\n%@",
[super description], [self ecStarted], alerter, sink];
}
- (oneway void) domanage: (NSString*)name

View file

@ -358,6 +358,11 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) ecDoLock;
/** Return the timestamp at which this process started up (when the
* receiver was initialised).
*/
- (NSDate*) ecStarted;
/** Release a lock on the shared EcProcess after thread-safe updates to
* process-wide variables.
*/

View file

@ -1305,7 +1305,7 @@ static NSString *noFiles = @"No log files to archive";
return cmdSignalled;
}
- (NSDate*) cmdStarted
- (NSDate*) ecStarted
{
return started;
}
@ -2788,7 +2788,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
else
{
[self cmdPrintf: @"\n%@ on %@ running since %@\n\n",
cmdLogName(), ecHostName(), [self cmdStarted]];
cmdLogName(), ecHostName(), [self ecStarted]];
if (NO == [cmdDefs boolForKey: @"Memory"])
{
@ -2814,7 +2814,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
else
{
[self cmdPrintf: @"\n%@ on %@ running since %@\n",
cmdLogName(), ecHostName(), [self cmdStarted]];
cmdLogName(), ecHostName(), [self ecStarted]];
if ([self cmdLastIP] != nil)
{
[self cmdPrintf: @"Last IP at %@\n", [self cmdLastIP]];
@ -3005,6 +3005,8 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
EcProc = self;
started = RETAIN([dateClass date]);
pinfo = [NSProcessInfo processInfo];
mgr = [NSFileManager defaultManager];
prf = EC_DEFAULTS_PREFIX;
@ -3208,8 +3210,6 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
}
}
started = RETAIN([dateClass date]);
/* See if we have a name specified for this process.
*/
ASSIGN(cmdName, [cmdDefs stringForKey: @"ProgramName"]);