use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.
the class CalendarItem method updateLocalExceptionsWhichMatchSeriesReply.
/**
* Exceptions can be created which aren't communicated to ATTENDEEs, either because the ORGANIZER wants to
* have local changes like a different alarm time or because a response is received which only affects one
* instance of a series.
* Caller is responsible for ensuring changed MetaData is written through to SQL sending notification of change.
*/
private void updateLocalExceptionsWhichMatchSeriesReply(Invite reply) throws ServiceException {
if ((reply == null) || reply.getRecurId() != null) {
// Only interested in series replies
return;
}
IRecurrence replyRecurrence = reply.getRecurrence();
if (replyRecurrence == null) {
sLog.debug("Giving up on trying to match series reply to local exceptions - no recurrence in reply");
return;
}
for (int i = 0; i < numInvites(); i++) {
Invite cur = getInvite(i);
if (!cur.classPropSetByMe() || (cur.getRecurId() == null)) {
continue;
}
ParsedDateTime recurIdDT = cur.getRecurId().getDt();
ParsedDateTime startDT = cur.getStartTime();
// If the start time has moved then the series response can't be applicable.
if ((recurIdDT == null) || (startDT == null) || !recurIdDT.sameTime(startDT)) {
continue;
}
long utcTime = recurIdDT.getUtcTime();
// Find instances within 2 seconds either side of start - assuming it will be a direct hit if found
List<Instance> instances = Recurrence.expandInstances(replyRecurrence, getId(), utcTime - 2000L, utcTime + 2000L);
if (instances == null || (instances.size() != 1)) {
continue;
}
cur.updateMatchingAttendeesFromReply(reply);
}
}
use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.
the class CalendarItem method processNewInviteReply.
boolean processNewInviteReply(Invite reply, String sender) throws ServiceException {
List<ZAttendee> attendees = reply.getAttendees();
String senderAddress = null;
if (sender != null && !sender.isEmpty()) {
try {
JavaMailInternetAddress address = new JavaMailInternetAddress(sender);
senderAddress = address.getAddress();
} catch (AddressException e) {
// ignore invalid sender address.
}
}
if (senderAddress != null && !attendees.isEmpty()) {
AccountAddressMatcher acctMatcher = null;
Account acct = Provisioning.getInstance().get(AccountBy.name, senderAddress);
if (acct != null) {
acctMatcher = new AccountAddressMatcher(acct);
}
Iterator<ZAttendee> iter = attendees.iterator();
while (iter.hasNext()) {
ZAttendee att = iter.next();
// Remove the attendee if not same as the sender.
if (!(att.addressMatches(senderAddress) || (acctMatcher != null && acctMatcher.matches(att.getAddress())))) {
iter.remove();
}
}
}
// trace logging
ZAttendee att1 = !attendees.isEmpty() ? attendees.get(0) : null;
if (att1 != null) {
String ptst = IcalXmlStrMap.sPartStatMap.toIcal(att1.getPartStat());
if (!reply.hasRecurId())
ZimbraLog.calendar.info("Processing CalendarItem reply: attendee=%s, partstat=%s, id=%d, folderId=%d, subject=\"%s\", UID=%s", att1.getAddress(), ptst, mId, getFolderId(), reply.isPublic() ? reply.getName() : "(private)", mUid);
else
ZimbraLog.calendar.info("Processing CalendarItem reply: attendee=%s, partstat=%s, id=%d, folderId=%d, subject=\"%s\", UID=%s, recurId=%s", att1.getAddress(), ptst, mId, getFolderId(), reply.isPublic() ? reply.getName() : "(private)", mUid, reply.getRecurId().getDtZ());
}
// Require private access permission only when we're replying to a private series/instance.
boolean requirePrivateCheck = requirePrivateCheck(reply);
OperationContext octxt = getMailbox().getOperationContext();
Account authAccount = octxt != null ? octxt.getAuthenticatedUser() : null;
boolean asAdmin = octxt != null ? octxt.isUsingAdminPrivileges() : false;
if (!canAccess(ACL.RIGHT_ACTION, authAccount, asAdmin, requirePrivateCheck))
throw ServiceException.PERM_DENIED("you do not have sufficient permissions to change this appointment/task's state");
boolean dirty = false;
// unique ID: UID+RECURRENCE_ID
// See RFC2446: 2.1.5 Message Sequencing
// UID already matches...next check if RecurId matches
// if so, then seqNo is next
// finally use DTStamp
Invite matchingInvite = matchingInvite(reply.getRecurId());
if (matchingInvite != null) {
// up to date with the organizer's event, provided there were no major changes.
if ((matchingInvite.isOrganizer() && (matchingInvite.getLastFullSeqNo() > reply.getSeqNo())) || (!matchingInvite.isOrganizer() && (matchingInvite.getSeqNo() > reply.getSeqNo()))) {
sLog.info("Invite-Reply %s is outdated (Calendar entry has higher SEQUENCE), ignoring!", reply);
return false;
}
// maybeStoreNewReply does some further checks which might invalidate this reply
// so, postpone updating attendee information until after that.
}
// they must be replying to a arbitrary instance)
for (ZAttendee at : attendees) {
if (mReplyList.maybeStoreNewReply(reply, at, this))
dirty = true;
}
if (!dirty) {
sLog.info("Invite-Reply %s is outdated ignoring!", reply);
return false;
}
if (matchingInvite != null) {
matchingInvite.updateMatchingAttendeesFromReply(reply);
updateLocalExceptionsWhichMatchSeriesReply(reply);
} else {
createPseudoExceptionForSingleInstanceReplyIfNecessary(reply);
}
saveMetadata();
return true;
}
use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.
the class CalendarItem method move.
@Override
boolean move(Folder target) throws ServiceException {
Invite defInv = getDefaultInviteOrNull();
String sbj;
if (defInv != null)
sbj = defInv.isPublic() ? defInv.getName() : "(private)";
else
sbj = "(none)";
ZimbraLog.calendar.info("Moving CalendarItem: id=%d, src=%s, dest=%s, subject=\"%s\", UID=%s", mId, getMailopContext(getFolder()), getMailopContext(target), sbj, mUid);
if (!isPublic()) {
if (!canAccess(ACL.RIGHT_PRIVATE))
throw ServiceException.PERM_DENIED("you do not have permission to move private calendar item from the current folder");
if (target.getId() != Mailbox.ID_FOLDER_TRASH && !target.canAccess(ACL.RIGHT_PRIVATE))
throw ServiceException.PERM_DENIED("you do not have permission to move private calendar item to the target folder");
}
addRevision(true);
return super.move(target);
}
use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.
the class CalendarItem method getNextAlarmHelperForTasks.
/**
* Find the next absolute trigger alarm. This is primarily for tasks. Tasks have a slightly different constraint
* on alarms than appointments do. In particular, the absolute trigger time of tasks need not be before DTSTART
* or DUE, whereas alarms for appointments are meaningful only if it triggers before DTSTART. A reminder for a
* meeting that has already started is useless, but a reminder for an over-due task can be quite useful.
*
* @param atOrAfter
* @param snoozeUntil
* @param forEmailAction
* @return
*/
private AlarmData getNextAlarmHelperForTasks(long atOrAfter, long snoozeUntil, boolean forEmailAction) {
// Find the two nearest alarms that surround atOrAfter such that t(alarm1) <= atOrAfter < t(alarm2).
Alarm alarm1 = null, alarm2 = null;
// trigger times for alarm1 and alarm2
long trigger1 = Long.MIN_VALUE, trigger2 = Long.MAX_VALUE;
// instance start time for alarm1 and alarm2
long instStart1 = 0, instStart2 = 0;
// invId and compNum for inst1 and inst2
int invId1 = 0, compNum1 = 0, invId2 = 0, compNum2 = 0;
for (Invite inv : mInvites) {
if (inv.isCancel())
continue;
// The invite can have multiple alarms.
for (Iterator<Alarm> alarms = inv.alarmsIterator(); alarms.hasNext(); ) {
Alarm alarm = alarms.next();
if (Action.EMAIL.equals(alarm.getAction()) == forEmailAction && alarm.getTriggerAbsolute() != null) {
long trg = alarm.getTriggerAbsolute().getUtcTime();
if (trg <= atOrAfter) {
if (trg > trigger1) {
trigger1 = trg;
alarm1 = alarm;
instStart1 = inv.getStartTime() != null ? inv.getStartTime().getUtcTime() : 0;
invId1 = inv.getMailItemId();
compNum1 = inv.getComponentNum();
}
} else {
// trg > atOrAfter
if (trg < trigger2) {
trigger2 = trg;
alarm2 = alarm;
instStart2 = inv.getStartTime() != null ? inv.getStartTime().getUtcTime() : 0;
invId2 = inv.getMailItemId();
compNum2 = inv.getComponentNum();
}
}
}
}
}
AlarmData ad1 = alarm1 != null ? new AlarmData(trigger1, snoozeUntil, instStart1, invId1, compNum1, alarm1) : null;
AlarmData ad2 = alarm2 != null ? new AlarmData(trigger2, AlarmData.NO_SNOOZE, instStart2, invId2, compNum2, alarm2) : null;
return chooseNextAlarm(atOrAfter, snoozeUntil, ad1, ad2);
}
use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.
the class CalendarItem method getSender.
@Override
public String getSender() {
String sender = null;
Invite firstInvite = getDefaultInviteOrNull();
if (firstInvite != null) {
ZOrganizer org = firstInvite.getOrganizer();
if (org != null)
sender = org.getIndexString();
}
return Strings.nullToEmpty(sender);
}
Aggregations