Merge to 2.3.20

This commit is contained in:
Francis Lachapelle committed 2017-03-10 11:14:52 -05:00
commit 2c8f56fb67
217 files changed
+5077 -734

No files matched your search

@@ -0,0 +1,60 @@
"Inviting the following persons is prohibited:" = "לא ניתן להזמין את אנשי הקשר הבאים: ";
"Personal Calendar" = "לוח שנה אישי";
vevent_class0 = "(אירוע פומבי)";
vevent_class1 = "(אירוע פרטי)";
vevent_class2 = "(אירוע סודי)";
vtodo_class0 = "(משימה פומבית)";
vtodo_class1 = "(משימה פרטית)";
vtodo_class2 = "(משימה סודית)";
/* Receipts */
"The event \"%{Summary}\" was created" = "האירוע \"{Summary}%\" נוצר";
"The event \"%{Summary}\" was deleted" = "האירוע \"{Summary}%\" נמחק";
"The event \"%{Summary}\" was updated" = "האירוע \"{Summary}%\" עודכן";
"The following attendees(s) were notified" = "המשתתפים הבאים קיבלו התראה";
"The following attendees(s) were added" = "המשתתפים הבאים הוספו";
"The following attendees(s) were removed" = "המשתתפים הבאים הוסרו";
/* IMIP messages */
"calendar_label" = "לוח שנה";
"startDate_label" = "התחלה";
"endDate_label" = "סיום";
"due_label" = "תאריך להגשה";
"location_label" = "מיקום";
"summary_label" = "תקציר";
"comment_label" = "הערה";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "הזמנה לאירוע: \"{Summary}%\"";
"(sent by %{SentBy}) " = "(מאת {SentBy}%)";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "{Organizer}% {SentByText}% הוזמנתם ל {Summary}%.\n\nהתחלה: {StartDate}%\nסיום: {EndDate}%\nתאור: {Description}%";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "{Organizer}% {SentByText}% הוזמנתם ל {Summary}%.\n\nהתחלה: {StartDate}% ב {StartTime}%\nסיום: {EndDate}% ב {EndTime}%\nתאור: {Description}%";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "אירוע מבוטל: \"{Summary}%\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "{Organizer}% {SentByText}% ביטלו את האירוע: {Summary}%.\n\nהתחלה: {StartDate}%\nסיום: {EndDate}%\nתאור: {Description}%";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "{Organizer}% {SentByText}% ביטלו את האירוע: {Summary}%.\n\nהתחלה: {StartDate}% ב {StartTime}%\nסיום: {EndDate}% ב {EndTime}%\nתאור: {Description}%";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "הפגישה \"{Summary}%\" עבור {OldStartDate}% שונתה";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "הפגישה \"{Summary}%\" עבור {OldStartDate}% ב {OldStartTime}% השתנתה";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "הפרמטרים הבאים השתנו בפגישה \"{Summary}%\":";
"Please accept or decline those changes."
= "נא לאשר או לבטל את השינויים";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "הזמנה אושרה: \"{Summary}%\"";
"Declined invitation: \"%{Summary}\"" = "הזמנה נדחתה: \"{Summary}%\"";
"Delegated invitation: \"%{Summary}\"" = "הזמנה הואצלה: \"{Summary}%\"";
"Not yet decided on invitation: \"%{Summary}\"" = "טרם הוחלט לגבי הזמנה: \"{Summary}%\"";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "{Attendee}% {SentByText}% אישר את הזמנתך.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "{Attendee}% {SentByText}% דחה את הזמנתך.";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "{Attendee}% {SentByText}% ההזמנה הואצלה ל {Delegate}%.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "{Attendee}% {SentByText}% טרם הוחלט לגבי הזמנתך.";
/* Resources */
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "לא ניתן לגשת למשאב: \"{Cn}% {SystemEmail}%\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "כמות מקסימלית של הזמנות בו זמנית ({NumberOfSimultaneousBookings}%) עבור המשאב \"{Cn}% {SystemEmail}%\". קיימת התנגשות באירוע \"{EventTitle}%\", המתחיל ב {StartDate}%.";
@@ -1305,17 +1305,13 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
NSMutableArray *ma;
NSDictionary *row;
NSCalendarDate *rangeEndDate;
unsigned int count, max;
max = [_records count];
ma = [NSMutableArray arrayWithCapacity: max];
// Adjust the range so it ends at midnight. This is necessary when calculating
// recurrences of all-day events.
rangeEndDate = [[_r endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:1];
_r = [NGCalendarDateRange calendarDateRangeWithStartDate: [_r startDate]
endDate: rangeEndDate];
endDate: [_r endDate]];
for (count = 0; count < max; count++)
{
+17 -3
View File
@@ -1776,6 +1776,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
NSArray *allEvents;
iCalEvent *event;
NSUInteger i;
int j;
allEvents = [rqCalendar events];
@@ -1808,12 +1809,27 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if (uid)
{
NSDictionary *defaultIdentity;
NSArray *allAttendees;
iCalPerson *attendee;
SOGoUser *organizer;
organizer = [SOGoUser userWithLogin: uid];
defaultIdentity = [organizer defaultIdentity];
[[event organizer] setCn: [defaultIdentity objectForKey: @"fullName"]];
[[event organizer] setEmail: [defaultIdentity objectForKey: @"email"]];
// We now check if one of the attendee is also the organizer. If so,
// we remove it. See bug #3905 (https://sogo.nu/bugs/view.php?id=3905)
// for more details. This is a Calendar app bug on Apple Yosemite.
allAttendees = [event attendees];
for (j = [allAttendees count]-1; j >= 0; j--)
{
attendee = [allAttendees objectAtIndex: j];
if ([organizer hasEmail: [attendee rfc822Email]])
[event removeFromAttendees: attendee];
}
}
}
}
@@ -1981,9 +1997,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
[self _decomposeGroupsInRequestCalendar: calendar];
if ([[ownerUser domainDefaults] iPhoneForceAllDayTransparency] && [rq isIPhone])
{
[self _adjustTransparencyInRequestCalendar: calendar];
}
[self _adjustTransparencyInRequestCalendar: calendar];
[self _adjustEventsInRequestCalendar: calendar];
[self adjustClassificationInRequestCalendar: calendar];
+29 -4
View File
@@ -618,7 +618,10 @@
if (content)
ASSIGN (originalCalendar, [iCalCalendar parseSingleFromSource: content]);
else
[self warnWithFormat: @"content not available, we will crash"];
{
[self warnWithFormat: @"content not available, we don't update the event"];
return;
}
}
oldMaster = (iCalRepeatableEntityObject *)
@@ -935,6 +938,9 @@
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
return;
// remove all alarms to avoid bug #3925
[event removeAllAlarms];
dd = [from domainDefaults];
if ([dd appointmentSendEMailNotifications] && [event isStillRelevant])
{
@@ -1231,12 +1237,31 @@
- (NSException *) moveToFolder: (SOGoGCSFolder *) newFolder
{
SOGoCalendarComponent *newComponent;
NSException *ex;
id o;
ex = [self copyToFolder: newFolder];
// Lookup to see if the event exists in the target calendar. During a MOVE, we do
// keep the ID of the event intact.
o = [newFolder lookupName: [self nameInContainer]
inContext: context
acquire: NO];
if (!ex)
ex = [self delete];
if ([o isKindOfClass: [NSException class]])
{
newComponent = [[self class] objectWithName: [self nameInContainer]
inContainer: newFolder];
ex = [newComponent saveCalendar: [self calendar: NO secure: NO]];
if (!ex)
ex = [self delete];
}
else
{
ex = [NSException exceptionWithHTTPStatus: 409
reason: @"Target exists - MOVE disallowed."];
}
return ex;
}
@@ -18,7 +18,7 @@ vtodo_class2 = "(Gizli görev)";
"calendar_label" = "Takvim";
"startDate_label" = "Başlangıç";
"endDate_label" = "Bitiş";
"due_label" = "Son Tarih";
"due_label" = "Kapanış Tarihi";
"location_label" = "Konum";
"summary_label" = "Özet";
"comment_label" = "Açıklama";
@@ -0,0 +1,2 @@
"Personal Address Book" = "אנשי קשר";
"Collected Address Book" = "אנשי קשר אשר נוצרו משליחת הודעה";
+2
View File
@@ -69,6 +69,8 @@ Mailer_RESOURCE_FILES += \
SOGoMailCroatianReply.wo \
SOGoMailGermanForward.wo \
SOGoMailGermanReply.wo \
SOGoMailHebrewForward.wo \
SOGoMailHebrewReply.wo \
SOGoMailHungarianForward.wo \
SOGoMailHungarianReply.wo \
SOGoMailIcelandicForward.wo \
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "משתשמשים אחרים";
"SharedFoldersName" = "תיקיות משותפות";
+1 -39
View File
@@ -1928,15 +1928,11 @@ static NSString *userAgent = nil;
//
- (NSException *) sendMailAndCopyToSent: (BOOL) copyToSent
{
NSMutableData *cleaned_message;
SOGoMailFolder *sentFolder;
SOGoDomainDefaults *dd;
NSURL *sourceIMAP4URL;
NSException *error;
NSData *message;
NSRange r1;
unsigned int limit;
// We strip the BCC fields prior sending any mails
NGMimeMessageGenerator *generator;
@@ -1944,43 +1940,9 @@ static NSString *userAgent = nil;
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
message = [generator generateMimeFromPart: [self mimeMessage]];
//
// We now look for the Bcc: header. If it is present, we remove it.
// Some servers, like qmail, do not remove it automatically.
//
#warning FIXME - we should fix the case issue when we switch to Pantomime
cleaned_message = [NSMutableData dataWithData: message];
// We search only in the headers so we start at 0 until
// we find \r\n\r\n, which is the headers delimiter
r1 = [cleaned_message rangeOfCString: "\r\n\r\n"];
limit = r1.location-1;
r1 = [cleaned_message rangeOfCString: "\r\nbcc: "
options: 0
range: NSMakeRange(0,limit)];
if (r1.location != NSNotFound)
{
// We search for the first \r\n AFTER the Bcc: header and
// replace the whole thing with \r\n.
unsigned int i;
for (i = r1.location+7; i < limit; i++)
{
if ([cleaned_message characterAtIndex: i] == '\r' &&
(i+1 < limit && [cleaned_message characterAtIndex: i+1] == '\n') &&
(i+2 < limit && !isspace([cleaned_message characterAtIndex: i+2])))
break;
}
[cleaned_message replaceBytesInRange: NSMakeRange(r1.location, i-r1.location)
withBytes: NULL
length: 0];
}
dd = [[context activeUser] domainDefaults];
error = [[SOGoMailer mailerWithDomainDefaults: dd]
sendMailData: cleaned_message
sendMailData: message
toRecipients: [self allBareRecipients]
sender: [self sender]
withAuthenticator: [self authenticatorInContext: context]
+3
View File
@@ -76,6 +76,9 @@
@interface SOGoMailGermanForward : SOGoMailForward
@end
@interface SOGoMailHebrewForward : SOGoMailForward
@end
@interface SOGoMailHungarianForward : SOGoMailForward
@end
+3
View File
@@ -287,6 +287,9 @@
@implementation SOGoMailGermanForward
@end
@implementation SOGoMailHebrewForward
@end
@implementation SOGoMailHungarianForward
@end
@@ -0,0 +1,16 @@
<#newLine/>
<#newLine/>
<#signaturePlacementOnTop><#newLine/>
<#signature/><#newLine/></#signaturePlacementOnTop>
-------- הודעה מקורית --------<#newLine/>
נושא: <#subject/><#newLine/>
תאריך: <#date/><#newLine/>
מאת: <#from/><#newLine/>
<#hasReplyTo>השב: <#replyTo/></#hasReplyTo><#hasOrganization>אירגון: <#organization/></#hasOrganization>אל: <#to/><#newLine/>
<#hasCc>מכותב: <#cc/></#hasCc><#hasNewsGroups>קבוצות חדשות: <#newsgroups/></#hasNewsGroups><#hasReferences>תזכור: <#references/></#hasReferences><#newLine/>
<#newLine/>
<#messageBody/><#newLine/>
<#signaturePlacementOnBottom><#newLine/>
<#newLine/>
<#signature/></#signaturePlacementOnBottom>
<#newLine/>
@@ -0,0 +1,88 @@
subject: WOString {
value = subject;
escapeHTML = NO;
}
date: WOString {
value = date;
escapeHTML = NO;
}
from: WOString {
value = from;
escapeHTML = NO;
}
newLine: WOString {
value = newLine;
escapeHTML = NO;
}
hasReplyTo: WOConditional {
condition = hasReplyTo;
}
replyTo: WOString {
value = replyTo;
escapeHTML = NO;
}
hasOrganization: WOConditional {
condition = hasOrganization;
}
organization: WOString {
value = organization;
escapeHTML = NO;
}
to: WOString {
value = to;
escapeHTML = NO;
}
hasCc: WOConditional {
condition = hasCc;
}
cc: WOString {
value = cc;
escapeHTML = NO;
}
hasNewsGroups: WOConditional {
condition = hasNewsGroups;
}
newsgroups: WOString {
value = newsgroups;
escapeHTML = NO;
}
hasReferences: WOConditional {
condition = hasReferences;
}
references: WOString {
value = references;
escapeHTML = NO;
}
messageBody: WOString {
value = messageBody;
escapeHTML = NO;
}
signature: WOString {
value = signature;
escapeHTML = NO;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}
@@ -0,0 +1,16 @@
<#replyPlacementOnTop><#newLine/>
<#newLine/>
</#replyPlacementOnTop><#signaturePlacementOnTop><#newLine/>
<#signature/><#newLine/>
</#signaturePlacementOnTop><#outlookMode>-------- הודעה מקורית --------<#newLine/>
נושא: <#subject/><#newLine/>
תאריך: <#date/><#newLine/>
מאת: <#from/><#newLine/>
<#hasReplyTo>השב: <#replyTo/></#hasReplyTo><#hasOrganization>אירגון: <#organization/></#hasOrganization>אל: <#to/><#newLine/>
<#hasCc>מכותב: <#cc/></#hasCc><#hasNewsGroups>קבוצות חדשות: <#newsgroups/></#hasNewsGroups><#hasReferences>תזכור: <#references/></#hasReferences></#outlookMode><#newLine/>
<#standardMode>פועל <#date/>, <#from/> כתב:</#standardMode><#newLine/>
<#newLine/>
<#messageBody/><#newLine/>
<#replyPlacementOnBottom><#newLine/>
<#newLine/>
</#replyPlacementOnBottom><#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom><#newLine/>
@@ -0,0 +1,106 @@
outlookMode: WOConditional {
condition = outlookMode;
}
standardMode: WOConditional {
condition = outlookMode;
negate = YES;
}
subject: WOString {
value = subject;
escapeHTML = NO;
}
date: WOString {
value = date;
escapeHTML = NO;
}
from: WOString {
value = from;
escapeHTML = NO;
}
newLine: WOString {
value = newLine;
escapeHTML = NO;
}
hasReplyTo: WOConditional {
condition = hasReplyTo;
}
replyTo: WOString {
value = replyTo;
escapeHTML = NO;
}
hasOrganization: WOConditional {
condition = hasOrganization;
}
organization: WOString {
value = organization;
escapeHTML = NO;
}
to: WOString {
value = to;
escapeHTML = NO;
}
hasCc: WOConditional {
condition = hasCc;
}
cc: WOString {
value = cc;
escapeHTML = NO;
}
hasNewsGroups: WOConditional {
condition = hasNewsGroups;
}
newsgroups: WOString {
value = newsgroups;
escapeHTML = NO;
}
hasReferences: WOConditional {
condition = hasReferences;
}
references: WOString {
value = references;
escapeHTML = NO;
}
messageBody: WOString {
value = messageBody;
escapeHTML = NO;
}
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;
}
+3
View File
@@ -75,6 +75,9 @@
@interface SOGoMailGermanReply : SOGoMailReply
@end
@interface SOGoMailHebrewReply : SOGoMailReply
@end
@interface SOGoMailHungarianReply : SOGoMailReply
@end
+3
View File
@@ -123,6 +123,9 @@
@implementation SOGoMailGermanReply
@end
@implementation SOGoMailHebrewReply
@end
@implementation SOGoMailHungarianReply
@end
+3 -1
View File
@@ -114,7 +114,9 @@ static memcached_st *handle = NULL;
if (handle)
{
memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 5);
sd = [SOGoSystemDefaults sharedSystemDefaults];
// We define the default value for cleaning up cached users'
+1
View File
@@ -53,6 +53,7 @@
"Finnish",
"French",
"German",
"Hebrew",
"Hungarian",
"Icelandic",
"Italian",
+18 -1
View File
@@ -439,7 +439,23 @@ static NSArray *childRecordFields = nil;
- (GCSFolder *) ocsFolderForPath: (NSString *) _path
{
return [[self folderManager] folderAtPath: _path];
NSDictionary *record;
SOGoCache *cache;
cache = [SOGoCache sharedCache];
record = [[cache valueForKey: _path] objectFromJSONString];
if (!record)
{
record = [[self folderManager] recordAtPath: _path];
if (!record)
return nil;
[cache setValue: [record jsonRepresentation] forKey: _path];
}
return [[self folderManager] folderForRecord: record];
}
- (BOOL) folderIsMandatory
@@ -590,6 +606,7 @@ static NSArray *childRecordFields = nil;
[self removeFolderSettings: moduleSettings
withReference: [self folderReference]];
[us synchronize];
[[SOGoCache sharedCache] removeValueForKey: ocsPath];
if ([[context request] handledByDefaultHandler])
[self sendFolderAdvisoryTemplate: @"Removal"];
+151
View File
@@ -40,6 +40,111 @@
#import "SOGoMailer.h"
//
// Useful extension that comes from Pantomime which is also
// released under the LGPL. We should eventually merge
// this with the same category found in SOPE's NGSmtpClient.m
// or simply drop sope-mime in favor of Pantomime
//
@interface NSMutableData (DataCleanupExtension)
- (unichar) characterAtIndex: (int) theIndex;
- (NSRange) rangeOfCString: (const char *) theCString;
- (NSRange) rangeOfCString: (const char *) theCString
options: (unsigned int) theOptions
range: (NSRange) theRange;
@end
@implementation NSMutableData (DataCleanupExtension)
- (unichar) characterAtIndex: (int) theIndex
{
const char *bytes;
int i, len;
len = [self length];
if (len == 0 || theIndex >= len)
{
[[NSException exceptionWithName: NSRangeException
reason: @"Index out of range."
userInfo: nil] raise];
return (unichar)0;
}
bytes = [self bytes];
for (i = 0; i < theIndex; i++)
{
bytes++;
}
return (unichar)*bytes;
}
- (NSRange) rangeOfCString: (const char *) theCString
{
return [self rangeOfCString: theCString
options: 0
range: NSMakeRange(0,[self length])];
}
-(NSRange) rangeOfCString: (const char *) theCString
options: (unsigned int) theOptions
range: (NSRange) theRange
{
const char *b, *bytes;
int i, len, slen;
if (!theCString)
{
return NSMakeRange(NSNotFound,0);
}
bytes = [self bytes];
len = [self length];
slen = strlen(theCString);
b = bytes;
if (len > theRange.location + theRange.length)
{
len = theRange.location + theRange.length;
}
if (theOptions == NSCaseInsensitiveSearch)
{
i = theRange.location;
b += i;
for (; i <= len-slen; i++, b++)
{
if (!strncasecmp(theCString,b,slen))
{
return NSMakeRange(i,slen);
}
}
}
else
{
i = theRange.location;
b += i;
for (; i <= len-slen; i++, b++)
{
if (!memcmp(theCString,b,slen))
{
return NSMakeRange(i,slen);
}
}
}
return NSMakeRange(NSNotFound,0);
}
@end
@implementation SOGoMailer
+ (SOGoMailer *) mailerWithDomainDefaults: (SOGoDomainDefaults *) dd
@@ -241,6 +346,52 @@
reason: @"cannot send message: no sender set"];
else
{
NSMutableData *cleaned_message;
NSRange r1;
unsigned int limit;
//
// We now look for the Bcc: header. If it is present, we remove it.
// Some servers, like qmail, do not remove it automatically.
//
#warning FIXME - we should fix the case issue when we switch to Pantomime
cleaned_message = [NSMutableData dataWithData: data];
// We search only in the headers so we start at 0 until
// we find \r\n\r\n, which is the headers delimiter
r1 = [cleaned_message rangeOfCString: "\r\n\r\n"];
limit = r1.location-1;
// We check if the mail actually *starts* with the Bcc: header
r1 = [cleaned_message rangeOfCString: "Bcc: "
options: 0
range: NSMakeRange(0,5)];
// It does not, let's search in the entire headers
if (r1.location == NSNotFound)
r1 = [cleaned_message rangeOfCString: "\r\nBcc: "
options: 0
range: NSMakeRange(0,limit)];
if (r1.location != NSNotFound)
{
// We search for the first \r\n AFTER the Bcc: header and
// replace the whole thing with \r\n.
unsigned int i;
for (i = r1.location+7; i < limit; i++)
{
if ([cleaned_message characterAtIndex: i] == '\r' &&
(i+1 < limit && [cleaned_message characterAtIndex: i+1] == '\n') &&
(i+2 < limit && !isspace([cleaned_message characterAtIndex: i+2])))
break;
}
[cleaned_message replaceBytesInRange: NSMakeRange(r1.location, i-r1.location+2)
withBytes: NULL
length: 0];
}
if ([mailingMechanism isEqualToString: @"sendmail"])
result = [self _sendmailSendData: data
toRecipients: recipients
+1 -7
View File
@@ -297,14 +297,8 @@ static SoSecurityManager *sm = nil;
// This is important because user A could delete folder X, and user B has subscribed to it.
// If the "default roles" are enabled for calendars/address books, -validatePersmission:.. will
// work (grabbing the default role) and the deleted resource will be incorrectly returned.
//
// FIXME - 2015/01/29 - this fix (24c6c8c91d421594bd51f07904d4cd3911cd187c) was reverted. Normally, we should add
// [subscribedFolder ocsFolderForPath: [subscribedFolder ocsPath]] to check the existence of the folder but it causes
// massive SQL traffic.
//
// The proper fix would be to check upon login and only upon login if GCS folders that we're subscribed to are still existent.
//
if (subscribedFolder
&& [subscribedFolder ocsFolderForPath: [subscribedFolder ocsPath]]
&& ![sm validatePermission: SOGoPerm_AccessObject
onObject: subscribedFolder
inContext: context])
+67 -26
View File
@@ -1,6 +1,6 @@
/* SOGoSieveManager.m - this file is part of SOGo
*
* Copyright (C) 2010-2015 Inverse inc.
* Copyright (C) 2010-2017 Inverse inc.
*
* Author: Inverse <info@inverse.ca>
*
@@ -20,9 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
@@ -366,7 +364,7 @@ static NSString *sieveScriptName = @"sogo";
}
else
scriptError = @"Rule lacks a 'value' parameter";
return (scriptError == nil);
}
@@ -784,7 +782,8 @@ static NSString *sieveScriptName = @"sogo";
SOGoDomainDefaults *dd;
NGSieveClient *client;
NSString *filterScript, *v;
BOOL b;
BOOL b, dateCapability;
unsigned int now;
dd = [user domainDefaults];
if (!([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled]))
@@ -797,7 +796,7 @@ static NSString *sieveScriptName = @"sogo";
if (!client)
return NO;
// We adjust the "methodRequirements" based on the server's
// We adjust the "methodRequirements" based on the server's
// capabilities. Cyrus exposes "imapflags" while Dovecot (and
// potentially others) expose "imap4flags" as specified in RFC5332
if ([client hasCapability: @"imap4flags"])
@@ -806,7 +805,9 @@ static NSString *sieveScriptName = @"sogo";
[methodRequirements setObject: @"imap4flags" forKey: @"removeflag"];
[methodRequirements setObject: @"imap4flags" forKey: @"flag"];
}
dateCapability = [client hasCapability: @"date"] && [client hasCapability: @"relational"];
//
// Now let's generate the script
//
@@ -832,16 +833,24 @@ static NSString *sieveScriptName = @"sogo";
// We handle vacation messages.
// See http://ietfreport.isoc.org/idref/draft-ietf-sieve-vacation/
values = [ud vacationOptions];
now = [[NSCalendarDate calendarDate] timeIntervalSince1970];
if (values && [[values objectForKey: @"enabled"] boolValue])
if (values && [[values objectForKey: @"enabled"] boolValue] &&
(![[values objectForKey: @"startDateEnabled"] boolValue] ||
dateCapability || [[values objectForKey: @"startDate"] intValue] < now) &&
(![[values objectForKey: @"endDateEnabled"] boolValue] ||
dateCapability || [[values objectForKey: @"endDate"] intValue] > now))
{
NSCalendarDate *startDate, *endDate;
NSMutableArray *allConditions;
NSMutableString *vacation_script;
NSArray *addresses;
NSString *text;
BOOL ignore, alwaysSend;
int days, i;
allConditions = [NSMutableArray array];
days = [[values objectForKey: @"daysBetweenResponse"] intValue];
addresses = [values objectForKey: @"autoReplyEmailAddresses"];
alwaysSend = [[values objectForKey: @"alwaysSend"] boolValue];
@@ -853,32 +862,64 @@ static NSString *sieveScriptName = @"sogo";
days = 7;
vacation_script = [NSMutableString string];
[req addObjectUniquely: @"vacation"];
// Skip mailing lists
if (ignore)
[vacation_script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) {"];
{
[allConditions addObject: @"not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"]"];
[allConditions addObject: @"not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"]"];
[allConditions addObject: @"not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\""];
}
// Start date of auto-reply
if ([[values objectForKey: @"startDateEnabled"] boolValue] && dateCapability)
{
[req addObjectUniquely: @"date"];
[req addObjectUniquely: @"relational"];
startDate = [NSCalendarDate dateWithTimeIntervalSince1970:
[[values objectForKey: @"startDate"] intValue]];
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"ge\" \"date\" \"%@\"",
[startDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
}
// End date of auto-reply
if ([[values objectForKey: @"endDateEnabled"] boolValue] && dateCapability)
{
[req addObjectUniquely: @"date"];
[req addObjectUniquely: @"relational"];
endDate = [NSCalendarDate dateWithTimeIntervalSince1970:
[[values objectForKey: @"endDate"] intValue]];
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"le\" \"date\" \"%@\"",
[endDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
}
// Apply conditions
if ([allConditions count])
[vacation_script appendFormat: @"if allof ( %@ ) { ",
[allConditions componentsJoinedByString: @", "]];
[vacation_script appendFormat: @"vacation :days %d :addresses [", days];
for (i = 0; i < [addresses count]; i++)
{
[vacation_script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
if (i == [addresses count]-1)
[vacation_script appendString: @"] "];
else
[vacation_script appendString: @", "];
}
[vacation_script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
if (ignore)
// Closing bracket of conditions
if ([allConditions count])
[vacation_script appendString: @"}\r\n"];
//
// See http://sogo.nu/bugs/view.php?id=2332 for details
// See https://sogo.nu/bugs/view.php?id=2332 for details
//
if (alwaysSend)
[script insertString: vacation_script atIndex: 0];
@@ -896,7 +937,7 @@ static NSString *sieveScriptName = @"sogo";
int i;
b = YES;
addresses = [values objectForKey: @"forwardAddress"];
if ([addresses isKindOfClass: [NSString class]])
addresses = [NSArray arrayWithObject: addresses];
@@ -907,11 +948,11 @@ static NSString *sieveScriptName = @"sogo";
if (v && [v length] > 0)
[script appendFormat: @"redirect \"%@\";\r\n", v];
}
if ([[values objectForKey: @"keepCopy"] boolValue])
[script appendString: @"keep;\r\n"];
}
if ([req count])
{
header = [NSString stringWithFormat: @"require [\"%@\"];\r\n",
@@ -925,7 +966,7 @@ static NSString *sieveScriptName = @"sogo";
result = [client setActiveScript: @""];
// We delete the existing Sieve script
result = [client deleteScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat: @"WARNING: Could not delete Sieve script - continuing...: %@", result];
}
@@ -935,13 +976,13 @@ static NSString *sieveScriptName = @"sogo";
if (b && [script length])
{
result = [client putScript: sieveScriptName script: script];
if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat: @"Could not upload Sieve script: %@", result];
[client closeConnection];
[client closeConnection];
return NO;
}
result = [client setActiveScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat: @"Could not enable Sieve script: %@", result];