use of com.zimbra.common.calendar.ParsedDateTime in project zm-mailbox by Zimbra.
the class CalendarItem method expandInstances.
/**
* Expand all the instances for the time period from start to end
*
* @param start
* @param end
* @param includeAlarmOnlyInstances
* @return list of Instances for the specified time period
*/
public Collection<Instance> expandInstances(long start, long end, boolean includeAlarmOnlyInstances) throws ServiceException {
long endAdjusted = end;
long alarmInstStart = 0;
if (includeAlarmOnlyInstances) {
// range.
if (mAlarmData != null) {
alarmInstStart = mAlarmData.getNextInstanceStart();
long nextAlarm = mAlarmData.getNextAtBase();
if (nextAlarm >= start && nextAlarm < end) {
if (alarmInstStart >= end)
endAdjusted = alarmInstStart + 1;
}
}
}
List<Instance> instances = new ArrayList<Instance>();
if (mRecurrence != null) {
long startTime = System.currentTimeMillis();
instances = Recurrence.expandInstances(mRecurrence, getId(), start, endAdjusted);
if (ZimbraLog.calendar.isDebugEnabled()) {
long elapsed = System.currentTimeMillis() - startTime;
ZimbraLog.calendar.debug("RECURRENCE EXPANSION for appt/task %s: start=%s, end=%s; took %sms. %s instances", getId(), start, end, elapsed, instances.size());
}
} else {
// organizer.
if (mInvites != null) {
for (Invite inv : mInvites) {
if (// Skip canceled instances.
inv.isCancel())
continue;
ParsedDateTime dtStart = inv.getStartTime();
long invStart = dtStart != null ? dtStart.getUtcTime() : 0;
ParsedDateTime dtEnd = inv.getEffectiveEndTime();
long invEnd = dtEnd != null ? dtEnd.getUtcTime() : 0;
if ((invStart < endAdjusted && invEnd > start) || (dtStart == null)) {
Instance inst = new Instance(getId(), new InviteInfo(inv), dtStart != null, dtEnd != null, invStart, invEnd, inv.isAllDayEvent(), dtStart != null ? dtStart.getOffset() : 0, dtEnd != null ? dtEnd.getOffset() : 0, inv.hasRecurId(), false);
instances.add(inst);
}
}
}
}
// Remove instances that aren't in the actual range.
for (Iterator<Instance> iter = instances.iterator(); iter.hasNext(); ) {
Instance inst = iter.next();
if (inst.hasStart() && inst.hasEnd()) {
long instStart = inst.getStart();
long instEnd = inst.getEnd();
// or instance starts after range end. (i.e. instance does not overlap range)
if (instStart != alarmInstStart && (instEnd <= start || instStart >= end))
iter.remove();
}
}
return instances;
}
use of com.zimbra.common.calendar.ParsedDateTime in project zm-mailbox by Zimbra.
the class CalendarItem method updateRecurrence.
private boolean updateRecurrence(long nextAlarm) throws ServiceException {
long startTime, endTime;
// update our recurrence rule, start with the initial rule
Invite firstInv = getDefaultInviteOrNull();
if (firstInv == null) {
return false;
}
IRecurrence recur = firstInv.getRecurrence();
if (recur instanceof Recurrence.RecurrenceRule) {
mRecurrence = (IRecurrence) recur.clone();
// now, go through the list of invites and find all the exceptions
for (Invite cur : mInvites) {
if (cur != firstInv) {
String method = cur.getMethod();
if (cur.isCancel()) {
assert (cur.hasRecurId());
if (cur.hasRecurId()) {
checkExdateIsSensible(cur.getRecurId());
Recurrence.CancellationRule cancelRule = new Recurrence.CancellationRule(cur.getRecurId());
((Recurrence.RecurrenceRule) mRecurrence).addException(cancelRule);
}
} else if (method.equals(ICalTok.REQUEST.toString()) || method.equals(ICalTok.PUBLISH.toString())) {
assert (cur.hasRecurId());
if (cur.hasRecurId() && cur.getStartTime() != null) {
checkRecurIdIsSensible(cur.getRecurId());
Recurrence.ExceptionRule exceptRule = null;
IRecurrence curRule = cur.getRecurrence();
if (curRule != null && curRule instanceof Recurrence.ExceptionRule) {
exceptRule = (Recurrence.ExceptionRule) curRule.clone();
} else {
// create a fake ExceptionRule wrapper around the single-instance
exceptRule = new Recurrence.ExceptionRule(cur.getRecurId(), cur.getStartTime(), cur.getEffectiveDuration(), new InviteInfo(cur));
}
((Recurrence.RecurrenceRule) mRecurrence).addException(exceptRule);
} else {
sLog.debug("Got second invite with no RecurID: " + cur.toString());
}
}
}
}
// Find the earliest DTSTART and latest DTEND. We're just looking for the bounds, so we won't worry
// about cancelled instances.
ParsedDateTime earliestStart = null;
ParsedDateTime latestEnd = null;
for (Invite cur : mInvites) {
if (!cur.isCancel()) {
ParsedDateTime start = cur.getStartTime();
if (earliestStart == null)
earliestStart = start;
else if (start != null && start.compareTo(earliestStart) < 0)
earliestStart = start;
ParsedDateTime end = cur.getEffectiveEndTime();
if (latestEnd == null)
latestEnd = end;
else if (end != null && end.compareTo(latestEnd) > 0)
latestEnd = end;
}
}
// Take the later of latestEnd and recurrence's end time.
ParsedDateTime recurEnd = mRecurrence.getEndTime();
if (latestEnd == null)
latestEnd = recurEnd;
else if (recurEnd != null && recurEnd.compareTo(latestEnd) > 0)
latestEnd = recurEnd;
// update the start and end time in the CalendarItem table if
// necessary
startTime = earliestStart != null ? earliestStart.getUtcTime() : 0;
endTime = latestEnd != null ? latestEnd.getUtcTime() : 0;
} else {
mRecurrence = null;
startTime = 0;
endTime = 0;
for (Invite inv : mInvites) {
if (!inv.isCancel()) {
ParsedDateTime dtStart = inv.getStartTime();
long st = dtStart != null ? dtStart.getUtcTime() : 0;
if (st != 0 && (st < startTime || startTime == 0))
startTime = st;
ParsedDateTime dtEnd = inv.getEffectiveEndTime();
long et = dtEnd != null ? dtEnd.getUtcTime() : 0;
if (et != 0 && et > endTime)
endTime = et;
}
}
}
// Adjust start/end times before recomputing alarm because alarm computation depends on those times.
boolean timesChanged = false;
if (mStartTime != startTime || mEndTime != endTime) {
timesChanged = true;
mStartTime = startTime;
mEndTime = endTime;
}
// Recompute next alarm. Bring appointment start time forward to the alarm time,
// if the next alarm is before the first instance.
recomputeNextAlarm(nextAlarm, false, false);
if (mAlarmData != null) {
long newNextAlarm = mAlarmData.getNextAtBase();
if (newNextAlarm > 0 && newNextAlarm < startTime && mStartTime != startTime) {
timesChanged = true;
mStartTime = newNextAlarm;
}
}
if (timesChanged) {
if (ZimbraLog.calendar.isDebugEnabled()) {
ZimbraLog.calendar.debug("Updating recurrence for %s. nextAlarm=%d.", getMailopContext(this), nextAlarm);
}
DbMailItem.updateInCalendarItemTable(this);
}
return true;
}
use of com.zimbra.common.calendar.ParsedDateTime in project zm-mailbox by Zimbra.
the class CalendarMailSender method createCalendarInviteDeniedMessage.
private static MimeMessage createCalendarInviteDeniedMessage(Account fromAccount, Account senderAccount, boolean onBehalfOf, boolean allowPrivateAccess, Address toAddr, Invite inv, MsgKey bodyTextKey) throws ServiceException {
Locale locale = !onBehalfOf ? fromAccount.getLocale() : senderAccount.getLocale();
Identity fromIdentity = getTargetedIdentity(fromAccount, inv);
StringBuilder replyText = new StringBuilder();
String sigText = getSignatureText(fromAccount, fromIdentity, Provisioning.A_zimbraPrefCalendarAutoDenySignatureId);
if (sigText == null || sigText.length() < 1)
sigText = L10nUtil.getMessage(bodyTextKey, locale);
if (sigText != null && sigText.length() > 0)
replyText.append(sigText).append("\r\n");
attachInviteSummary(replyText, inv, null, locale);
String subject = L10nUtil.getMessage(MsgKey.calendarReplySubjectDecline, locale) + ": " + inv.getName();
String uid = inv.getUid();
ParsedDateTime exceptDt = null;
if (inv.hasRecurId())
exceptDt = inv.getRecurId().getDt();
Invite replyInv = replyToInvite(fromAccount, senderAccount, onBehalfOf, allowPrivateAccess, inv, VERB_DECLINE, subject, exceptDt);
ZVCalendar iCal = replyInv.newToICalendar(true);
Address fromAddr = fromIdentity.getFriendlyEmailAddress();
Address senderAddr = null;
if (onBehalfOf)
senderAddr = AccountUtil.getFriendlyEmailAddress(senderAccount);
List<Address> toAddrs = new ArrayList<Address>(1);
toAddrs.add(toAddr);
return createCalendarMessage(senderAccount, fromAddr, senderAddr, toAddrs, subject, replyText.toString(), null, uid, iCal);
}
use of com.zimbra.common.calendar.ParsedDateTime in project zm-mailbox by Zimbra.
the class CalendarMailSender method createCancelMessage.
public static MimeMessage createCancelMessage(Account fromAccount, Account senderAccount, boolean asAdmin, boolean onBehalfOf, List<Address> toAddrs, CalendarItem calItem, Invite inv, String text, ZVCalendar iCal) throws ServiceException {
Locale locale = !onBehalfOf ? fromAccount.getLocale() : senderAccount.getLocale();
Invite defaultInv = calItem.getDefaultInviteOrNull();
boolean hidePrivate = !calItem.isPublic() && !calItem.allowPrivateAccess(senderAccount, asAdmin);
String invSubject;
if (hidePrivate)
invSubject = L10nUtil.getMessage(MsgKey.calendarSubjectWithheld, locale);
else
invSubject = inv != null ? inv.getName() : "";
String sbj = getCancelSubject(invSubject, locale);
StringBuilder sb = new StringBuilder(text);
sb.append("\r\n\r\n");
if (!inv.equals(defaultInv) && inv.getStartTime() != null && inv.getRecurId() != null) {
sb.append(L10nUtil.getMessage(MsgKey.calendarCancelAppointmentInstanceWhich, locale));
sb.append(" ");
ParsedDateTime start = inv.getStartTime();
TimeZone tz = start.getTimeZone();
Date startDate = new Date(start.getUtcTime());
sb.append(CalendarMailSender.formatDateTime(startDate, tz, locale));
sb.append("\r\n\r\n");
}
if (!hidePrivate) {
MimeMessage mmInv = inv.getMimeMessage();
if (mmInv == null && defaultInv != null)
mmInv = defaultInv.getMimeMessage();
if (mmInv != null)
attachInviteSummary(sb, inv, mmInv, locale);
}
Address from = AccountUtil.getFriendlyEmailAddress(fromAccount);
Address sender = null;
if (onBehalfOf)
sender = AccountUtil.getFriendlyEmailAddress(senderAccount);
return createCalendarMessage(senderAccount, from, sender, toAddrs, sbj, sb.toString(), null, defaultInv != null ? defaultInv.getUid() : "unknown", iCal);
}
use of com.zimbra.common.calendar.ParsedDateTime in project zm-mailbox by Zimbra.
the class Alarm method decodeMetadata.
/**
* Create an Alarm from Metadata. Return value may be null.
* @param meta
* @return
* @throws ServiceException
* @throws ParseException
*/
public static Alarm decodeMetadata(Metadata meta) throws ServiceException {
Action action = expandAction(meta.get(FN_ACTION));
if (!actionAllowed(action))
return null;
TriggerType tt = expandTriggerType(meta.get(FN_TRIGGER_TYPE));
TriggerRelated triggerRelated = null;
ParsedDuration triggerRelative = null;
ParsedDateTime triggerAbsolute = null;
if (TriggerType.ABSOLUTE.equals(tt)) {
try {
triggerAbsolute = ParsedDateTime.parseUtcOnly(meta.get(FN_TRIGGER_ABSOLUTE));
} catch (ParseException e) {
throw ServiceException.FAILURE("Error parsing metadata for alarm", e);
}
} else {
triggerRelative = ParsedDuration.parse(meta.get(FN_TRIGGER_RELATIVE));
triggerRelated = expandTriggerRelated(meta.get(FN_TRIGGER_RELATED, null));
}
ParsedDuration repeatDuration = null;
int repeatCount = 0;
String val = meta.get(FN_REPEAT_DURATION, null);
if (val != null) {
repeatDuration = ParsedDuration.parse(val);
repeatCount = (int) meta.getLong(FN_REPEAT_COUNT, 0);
}
String description = meta.get(FN_DESCRIPTION, null);
String summary = meta.get(FN_SUMMARY, null);
Attach attach = null;
Metadata metaAttach = meta.getMap(FN_ATTACH, true);
if (metaAttach != null)
attach = Util.decodeAttachFromMetadata(metaAttach);
int numAts = (int) meta.getLong(FN_NUM_ATTENDEES, 0);
List<ZAttendee> attendees = new ArrayList<ZAttendee>(numAts);
for (int i = 0; i < numAts; i++) {
try {
Metadata metaAttendee = meta.getMap(FN_ATTENDEE + i, true);
if (metaAttendee != null)
attendees.add(new ZAttendee(metaAttendee));
} catch (ServiceException e) {
ZimbraLog.calendar.warn("Problem decoding attendee " + i + " in ALARM ");
}
}
Alarm alarm = new Alarm(action, tt, triggerRelated, triggerRelative, triggerAbsolute, repeatDuration, repeatCount, description, summary, attach, attendees, Util.decodeXPropsFromMetadata(meta));
return alarm;
}
Aggregations