2010-08-20 03:40:07 +02:00
|
|
|
/* SOGoEAlarmsNotifier.m - this file is part of SOGo
|
|
|
|
*
|
2016-11-02 23:16:45 +01:00
|
|
|
* Copyright (C) 2011-2016 Inverse inc.
|
2010-08-20 03:40:07 +02:00
|
|
|
*
|
|
|
|
* This file is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This file is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2012-10-22 16:09:13 +02:00
|
|
|
#import <Foundation/NSDictionary.h>
|
2010-08-20 03:40:07 +02:00
|
|
|
#import <Foundation/NSProcessInfo.h>
|
2013-08-27 19:12:03 +02:00
|
|
|
#import <Foundation/NSUserDefaults.h>
|
2010-08-20 03:40:07 +02:00
|
|
|
|
|
|
|
#import <NGExtensions/NGHashMap.h>
|
|
|
|
#import <NGExtensions/NGQuotedPrintableCoding.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
|
|
#import <NGMail/NGMimeMessage.h>
|
|
|
|
|
|
|
|
#import <NGCards/iCalAlarm.h>
|
2017-04-12 14:59:29 +02:00
|
|
|
#import <NGCards/iCalEvent.h>
|
2010-08-20 03:40:07 +02:00
|
|
|
|
|
|
|
#import <SOGo/NSCalendarDate+SOGo.h>
|
|
|
|
#import <SOGo/NSString+Utilities.h>
|
2016-11-02 23:16:45 +01:00
|
|
|
#import <SOGo/SOGoCredentialsFile.h>
|
2010-08-20 03:40:07 +02:00
|
|
|
#import <SOGo/SOGoMailer.h>
|
|
|
|
#import <SOGo/SOGoProductLoader.h>
|
|
|
|
#import <SOGo/SOGoUser.h>
|
2017-04-12 14:59:29 +02:00
|
|
|
#import <SOGo/SOGoUserManager.h>
|
|
|
|
#import <SOGo/NSDictionary+Utilities.m>
|
|
|
|
#import <SOGo/NSObject+Utilities.h>
|
|
|
|
#import <SOGo/SOGoUserFolder.h>
|
2016-11-02 23:16:45 +01:00
|
|
|
#import <Appointments/iCalEntityObject+SOGo.h>
|
2010-08-20 03:40:07 +02:00
|
|
|
#import <Appointments/iCalPerson+SOGo.h>
|
|
|
|
#import <Appointments/SOGoEMailAlarmsManager.h>
|
2017-04-12 14:59:29 +02:00
|
|
|
#import <Appointments/SOGoAppointmentFolder.h>
|
2017-06-16 19:24:24 +02:00
|
|
|
#import <Appointments/SOGoAppointmentFolders.h>
|
2017-04-12 14:59:29 +02:00
|
|
|
|
|
|
|
#import <NGObjWeb/WOApplication.h>
|
|
|
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
|
|
|
#import <Appointments/SOGoAptMailReminder.h>
|
|
|
|
#import <WEExtensions/WEResourceManager.h>
|
2010-08-20 03:40:07 +02:00
|
|
|
|
|
|
|
#import "SOGoEAlarmsNotifier.h"
|
|
|
|
|
|
|
|
@implementation SOGoEAlarmsNotifier
|
|
|
|
|
2013-08-27 19:12:03 +02:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]))
|
|
|
|
{
|
|
|
|
staticAuthenticator = nil;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[staticAuthenticator release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
- (NSString *) _messageID
|
|
|
|
{
|
|
|
|
static int pid = 0;
|
|
|
|
static int sequence = 0;
|
|
|
|
NSString *messageID, *pGUID;
|
|
|
|
int timestamp;
|
|
|
|
|
|
|
|
if (pid == 0)
|
|
|
|
pid = getpid();
|
|
|
|
sequence++;
|
|
|
|
timestamp = (int) [[NSDate date] timeIntervalSince1970];
|
|
|
|
pGUID = [[NSProcessInfo processInfo] globallyUniqueString];
|
|
|
|
|
2015-10-31 07:10:03 +01:00
|
|
|
messageID = [NSString stringWithFormat: @"<%0X-%0X-%0X-%0X@%lu>",
|
|
|
|
pid, timestamp, sequence, (unsigned int)random(), [pGUID hash]];
|
2010-08-20 03:40:07 +02:00
|
|
|
|
|
|
|
return [messageID lowercaseString];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NGMutableHashMap *) _headersForAlarm: (iCalAlarm *) alarm
|
|
|
|
withOwner: (SOGoUser *) owner
|
2017-04-12 14:59:29 +02:00
|
|
|
withSubject: (NSString *) subject
|
2010-08-20 03:40:07 +02:00
|
|
|
{
|
|
|
|
NGMutableHashMap *headers;
|
2017-04-12 14:59:29 +02:00
|
|
|
NSString *dateString, *fullName, *email;
|
2010-08-20 03:40:07 +02:00
|
|
|
NSDictionary *identity;
|
|
|
|
|
|
|
|
headers = [NGMutableHashMap hashMap];
|
|
|
|
|
|
|
|
[headers addObject: subject forKey: @"Subject"];
|
|
|
|
dateString = [[NSCalendarDate date] rfc822DateString];
|
|
|
|
[headers addObject: dateString forKey: @"Date"];
|
|
|
|
[headers addObject: @"1.0" forKey: @"MIME-Version"];
|
|
|
|
[headers addObject: @"SOGo Alarms Notifier/1.0" forKey: @"User-Agent"];
|
|
|
|
[headers addObject: @"high" forKey: @"Importance"];
|
|
|
|
[headers addObject: @"1" forKey: @"X-Priority"];
|
2017-04-12 14:59:29 +02:00
|
|
|
[headers setObject: @"text/html; charset=\"utf-8\"" forKey: @"Content-Type"];
|
2010-08-20 03:40:07 +02:00
|
|
|
[headers setObject: @"quoted-printable" forKey: @"Content-Transfer-Encoding"];
|
|
|
|
|
|
|
|
identity = [owner primaryIdentity];
|
2017-04-12 14:59:29 +02:00
|
|
|
fullName = [identity objectForKey: @"fullName"];
|
2010-08-20 03:40:07 +02:00
|
|
|
if ([fullName length])
|
|
|
|
email = [NSString stringWithFormat: @"%@ <%@>", fullName,
|
|
|
|
[identity objectForKey: @"email"]];
|
|
|
|
else
|
|
|
|
email = [identity objectForKey: @"email"];
|
|
|
|
[headers addObject: email forKey: @"From"];
|
|
|
|
|
|
|
|
return headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _sendMessageWithHeaders: (NGMutableHashMap *) headers
|
|
|
|
content: (NSData *) content
|
2017-06-09 21:17:32 +02:00
|
|
|
to: (NSDictionary *) to
|
2010-08-20 03:40:07 +02:00
|
|
|
withMailer: (SOGoMailer *) mailer
|
|
|
|
{
|
|
|
|
NGMimeMessage *message;
|
2017-06-09 21:17:32 +02:00
|
|
|
NSString *headerTo;
|
2010-08-20 03:40:07 +02:00
|
|
|
|
2017-06-09 21:17:32 +02:00
|
|
|
headerTo = [NSString stringWithFormat: @"%@ <%@>", [to objectForKey: @"fullName"],
|
|
|
|
[to objectForKey: @"email"]];
|
2011-12-12 17:39:56 +01:00
|
|
|
[headers setObject: headerTo forKey: @"To"];
|
2010-08-20 03:40:07 +02:00
|
|
|
[headers setObject: [self _messageID] forKey: @"Message-Id"];
|
|
|
|
message = [NGMimeMessage messageWithHeader: headers];
|
|
|
|
[message setBody: content];
|
2012-10-16 22:56:48 +02:00
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
[mailer sendMimePart: message
|
2017-06-09 21:17:32 +02:00
|
|
|
toRecipients: [NSArray arrayWithObject: [to objectForKey: @"email"]]
|
|
|
|
sender: [to objectForKey: @"email"]
|
2013-08-27 19:12:03 +02:00
|
|
|
withAuthenticator: staticAuthenticator inContext: nil];
|
2010-08-20 03:40:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _processAlarm: (iCalAlarm *) alarm
|
|
|
|
withOwner: (NSString *) ownerId
|
2017-04-12 14:59:29 +02:00
|
|
|
andContainerPath: (NSString *) containerPath
|
2010-08-20 03:40:07 +02:00
|
|
|
{
|
|
|
|
NGMutableHashMap *headers;
|
2017-06-09 21:17:32 +02:00
|
|
|
NSArray *parts;
|
2010-08-20 03:40:07 +02:00
|
|
|
NSData *content, *qpContent;
|
|
|
|
SOGoMailer *mailer;
|
2017-06-09 21:17:32 +02:00
|
|
|
NSString *subject;
|
2010-08-20 03:40:07 +02:00
|
|
|
SOGoUser *owner;
|
|
|
|
|
2017-04-12 14:59:29 +02:00
|
|
|
WOContext *localContext;
|
|
|
|
WOApplication *app;
|
|
|
|
SOGoAptMailReminder *p;
|
|
|
|
NSString *pageName;
|
|
|
|
WOResourceManager *rm;
|
|
|
|
|
|
|
|
SOGoAppointmentFolders *folders;
|
|
|
|
SOGoAppointmentFolder *folder;
|
|
|
|
SOGoUserFolder *userFolder;
|
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
owner = [SOGoUser userWithLogin: ownerId];
|
|
|
|
mailer = [SOGoMailer mailerWithDomainDefaults: [owner domainDefaults]];
|
|
|
|
|
2017-04-12 14:59:29 +02:00
|
|
|
localContext = [WOContext context];
|
|
|
|
[localContext setActiveUser: owner];
|
|
|
|
app = [[WOApplication alloc] initWithName: @"SOGo"];
|
|
|
|
|
|
|
|
rm = [[WEResourceManager alloc] init];
|
2017-06-09 21:17:32 +02:00
|
|
|
[app setResourceManager: rm];
|
2017-04-12 14:59:29 +02:00
|
|
|
[rm release];
|
|
|
|
[app _setCurrentContext:localContext];
|
|
|
|
|
|
|
|
userFolder = [[localContext activeUser] homeFolderInContext: localContext ];
|
|
|
|
folders = [userFolder privateCalendars: @"Calendar"
|
2017-06-09 21:17:32 +02:00
|
|
|
inContext: localContext];
|
2017-04-12 14:59:29 +02:00
|
|
|
|
|
|
|
pageName = [NSString stringWithFormat: @"SOGoAptMail%@", @"Reminder"];
|
|
|
|
|
|
|
|
p = [app pageWithName: pageName inContext: localContext];
|
|
|
|
|
|
|
|
parts = [containerPath componentsSeparatedByString: @"/"];
|
|
|
|
if ([parts count] > 4)
|
|
|
|
{
|
|
|
|
folder = [folders lookupName: [parts objectAtIndex: 4]
|
|
|
|
inContext: localContext
|
|
|
|
acquire: NO];
|
|
|
|
[p setCalendarName: [folder displayName]];
|
|
|
|
}
|
|
|
|
|
|
|
|
[p setApt: [alarm parent]];
|
|
|
|
[p setAttendees: [[alarm parent] attendees]];
|
|
|
|
|
|
|
|
content = [[p getBody] dataUsingEncoding: NSUTF8StringEncoding];
|
|
|
|
subject = [p getSubject];
|
|
|
|
|
|
|
|
headers = [self _headersForAlarm: alarm withOwner: owner withSubject: subject];
|
2010-08-20 03:40:07 +02:00
|
|
|
qpContent = [content dataByEncodingQuotedPrintable];
|
2017-06-09 21:17:32 +02:00
|
|
|
[self _sendMessageWithHeaders: headers
|
|
|
|
content: qpContent
|
|
|
|
to: [owner primaryIdentity]
|
|
|
|
withMailer: mailer];
|
2010-08-20 03:40:07 +02:00
|
|
|
}
|
|
|
|
|
2013-08-27 19:12:03 +02:00
|
|
|
- (void) usage
|
|
|
|
{
|
|
|
|
fprintf (stderr, "sogo-ealarms-notify [-p credentialFile] [-h]\n\n"
|
|
|
|
" -p credentialFile Specify the file containing credentials to use for SMTP AUTH\n"
|
|
|
|
" The file should contain a single line:\n"
|
|
|
|
" username:password\n"
|
|
|
|
" -h This message\n"
|
|
|
|
"\n"
|
|
|
|
"This program should be configured to run every minute from a crontab.\n");
|
|
|
|
}
|
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
- (BOOL) run
|
|
|
|
{
|
2016-11-02 23:16:45 +01:00
|
|
|
NSCalendarDate *startDate, *toDate;
|
2010-08-20 03:40:07 +02:00
|
|
|
SOGoEMailAlarmsManager *eaMgr;
|
2016-11-02 23:16:45 +01:00
|
|
|
NSMutableArray *metadata;
|
|
|
|
iCalEntityObject *entity;
|
2013-08-27 19:12:03 +02:00
|
|
|
SOGoCredentialsFile *cf;
|
|
|
|
NSString *credsFilename;
|
2016-11-02 23:16:45 +01:00
|
|
|
NSDictionary *d;
|
|
|
|
NSArray *alarms;
|
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
int count, max;
|
|
|
|
|
2017-07-04 19:15:29 +02:00
|
|
|
[[SOGoProductLoader productLoader] loadAllProducts: NO];
|
2017-04-12 14:59:29 +02:00
|
|
|
|
2013-08-27 19:12:03 +02:00
|
|
|
if ([[NSUserDefaults standardUserDefaults] stringForKey: @"h"])
|
|
|
|
{
|
|
|
|
[self usage];
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
credsFilename = [[NSUserDefaults standardUserDefaults] stringForKey: @"p"];
|
|
|
|
if (credsFilename)
|
|
|
|
{
|
|
|
|
cf = [SOGoCredentialsFile credentialsFromFile: credsFilename];
|
|
|
|
if (!cf)
|
|
|
|
return NO;
|
|
|
|
staticAuthenticator =
|
|
|
|
[SOGoStaticAuthenticator authenticatorWithUser: [cf username]
|
|
|
|
andPassword: [cf password]];
|
|
|
|
[staticAuthenticator retain];
|
|
|
|
}
|
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
eaMgr = [NSClassFromString (@"SOGoEMailAlarmsManager")
|
|
|
|
sharedEMailAlarmsManager];
|
|
|
|
|
2016-11-02 23:16:45 +01:00
|
|
|
metadata = [[NSMutableArray alloc] init];
|
2010-08-20 03:40:07 +02:00
|
|
|
startDate = [NSCalendarDate calendarDate];
|
|
|
|
toDate = [startDate addYear: 0 month: 0 day: 0
|
|
|
|
hour: 0 minute: 0
|
|
|
|
second: -[startDate secondOfMinute]];
|
|
|
|
alarms = [eaMgr scheduledAlarmsFromDate: [toDate addYear: 0 month: 0 day: 0
|
|
|
|
hour: 0 minute: -5
|
|
|
|
second: 0]
|
|
|
|
toDate: toDate
|
2016-11-02 23:16:45 +01:00
|
|
|
withMetadata: metadata];
|
2017-04-12 14:59:29 +02:00
|
|
|
|
2010-08-20 03:40:07 +02:00
|
|
|
max = [alarms count];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
[self _processAlarm: [alarms objectAtIndex: count]
|
2017-04-12 14:59:29 +02:00
|
|
|
withOwner: [[metadata objectAtIndex: count] objectForKey: @"owner"]
|
|
|
|
andContainerPath: [[[metadata objectAtIndex: count] objectForKey: @"record"] objectForKey: @"c_path"]];
|
2016-11-02 23:16:45 +01:00
|
|
|
|
|
|
|
// We now update the next alarm date (if any, for recurring
|
|
|
|
// events or tasks for example). This will also delete any emai
|
|
|
|
// alarms that are no longer relevant
|
|
|
|
max = [metadata count];
|
|
|
|
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
d = [metadata objectAtIndex: count];
|
|
|
|
entity = [d objectForKey: @"entity"];
|
|
|
|
[entity quickRecordFromContent: nil
|
|
|
|
container: [d objectForKey: @"container"]
|
|
|
|
nameInContainer: [[d objectForKey: @"record"] objectForKey: @"c_name"]];
|
|
|
|
}
|
2010-08-20 03:40:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|