use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class CancelCalendarItem method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Account acct = getRequestedAccount(zsc);
Mailbox mbox = getRequestedMailbox(zsc);
OperationContext octxt = getOperationContext(zsc, context);
ItemId iid = new ItemId(request.getAttribute(MailConstants.A_ID), zsc);
if (!iid.hasSubpart())
throw ServiceException.INVALID_REQUEST("missing invId subpart: id should be specified as \"item-inv\"", null);
int compNum = (int) request.getAttributeLong(MailConstants.E_INVITE_COMPONENT);
CalendarItem calItem = mbox.getCalendarItemById(octxt, iid.getId());
if (calItem == null)
throw MailServiceException.NO_SUCH_CALITEM(iid.getId(), " for CancelCalendarItemRequest(" + iid + "," + compNum + ")");
if (calItem.inTrash())
throw ServiceException.INVALID_REQUEST("cannot cancel a calendar item under trash", null);
// We probably don't want to bother with conflict check for a cancel request...
Invite inv = calItem.getInvite(iid.getSubpartId(), compNum);
if (inv == null)
throw MailServiceException.INVITE_OUT_OF_DATE(iid.toString());
MailSendQueue sendQueue = new MailSendQueue();
try {
Element recurElt = request.getOptionalElement(MailConstants.E_INSTANCE);
if (recurElt != null) {
TimeZoneMap tzmap = inv.getTimeZoneMap();
Element tzElem = request.getOptionalElement(MailConstants.E_CAL_TZ);
ICalTimeZone tz = null;
if (tzElem != null) {
tz = CalendarUtils.parseTzElement(tzElem);
tzmap.add(tz);
}
RecurId recurId = CalendarUtils.parseRecurId(recurElt, tzmap);
// trace logging
ZimbraLog.calendar.info("<CancelCalendarItem> id=%d, folderId=%d, subject=\"%s\", UID=%s, recurId=%s", calItem.getId(), calItem.getFolderId(), inv.isPublic() ? inv.getName() : "(private)", calItem.getUid(), recurId.getDtZ());
Element msgElem = request.getOptionalElement(MailConstants.E_MSG);
cancelInstance(zsc, octxt, msgElem, acct, mbox, calItem, inv, recurId, inv.getAttendees(), sendQueue);
} else {
// if recur is not set, then we're canceling the entire calendar item...
// trace logging
ZimbraLog.calendar.info("<CancelCalendarItem> id=%d, folderId=%d, subject=\"%s\", UID=%s", calItem.getId(), calItem.getFolderId(), inv.isPublic() ? inv.getName() : "(private)", calItem.getUid());
Invite seriesInv = calItem.getDefaultInviteOrNull();
if (seriesInv != null) {
if (seriesInv.getMethod().equals(ICalTok.REQUEST.toString()) || seriesInv.getMethod().equals(ICalTok.PUBLISH.toString())) {
if (seriesInv.isOrganizer()) {
// Send cancel notice to attendees who were invited to exception instances only.
// These attendees need to be notified separately because they aren't included in the series
// cancel notice.
List<ZAttendee> atsSeries = seriesInv.getAttendees();
Invite[] invs = calItem.getInvites();
long now = octxt != null ? octxt.getTimestamp() : System.currentTimeMillis();
for (Invite exceptInv : invs) {
if (exceptInv != seriesInv) {
String mthd = exceptInv.getMethod();
if ((mthd.equals(ICalTok.REQUEST.toString()) || mthd.equals(ICalTok.PUBLISH.toString())) && inviteIsAfterTime(exceptInv, now)) {
List<ZAttendee> atsExcept = exceptInv.getAttendees();
// Find exception instance attendees who aren't series attendees.
List<ZAttendee> ats = CalendarUtils.getRemovedAttendees(atsExcept, atsSeries, false, acct);
if (!ats.isEmpty()) {
// notify ats
cancelInstance(zsc, octxt, null, acct, mbox, calItem, exceptInv, exceptInv.getRecurId(), ats, sendQueue);
}
}
}
}
}
// Finally, cancel the series.
Element msgElem = request.getOptionalElement(MailConstants.E_MSG);
cancelInvite(zsc, octxt, msgElem, acct, mbox, calItem, seriesInv, sendQueue);
}
// disable change constraint checking since we've just successfully done a modify
octxt = new OperationContext(octxt).unsetChangeConstraint();
}
}
} finally {
sendQueue.send();
}
Element response = getResponseElement(zsc);
return response;
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class CalendarUtils method parseRecurId.
static RecurId parseRecurId(Element e, TimeZoneMap tzmap) throws ServiceException {
String range = e.getAttribute(MailConstants.A_CAL_RANGE, null);
ParsedDateTime dt = parseDateTime(e, tzmap);
return new RecurId(dt, range);
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class Mailbox method processICalReplies.
private void processICalReplies(OperationContext octxt, ZVCalendar cal, String sender) throws ServiceException {
// Reply from Outlook will usually have PRODID set to the following:
//
// Outlook2007+ZCO: PRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN
// Outlook2010+ZCO: PRODID:-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN
// Outlook20xx+Exchange: PRODID:Microsoft Exchange Server 2007
// (if Exchange is Exchange 2007; Exchange 2010 probably works similarly)
//
// Lowest common denominator is "Microsoft" substring.
String prodId = cal.getPropVal(ICalTok.PRODID, null);
boolean fromOutlook = prodId != null && prodId.toLowerCase().contains("microsoft");
AccountAddressMatcher acctMatcher = new AccountAddressMatcher(getAccount());
List<Invite> components = Invite.createFromCalendar(getAccount(), null, cal, false);
for (Invite inv : components) {
String orgAddress;
if (inv.hasOrganizer()) {
ZOrganizer org = inv.getOrganizer();
orgAddress = org.getAddress();
} else {
ZimbraLog.calendar.warn("No ORGANIZER found in REPLY. Assuming current mailbox.");
orgAddress = getAccount().getName();
}
if (acctMatcher.matches(orgAddress)) {
// RECURRENCE-ID.
if (fromOutlook && !inv.isAllDayEvent() && inv.hasRecurId()) {
RecurId rid = inv.getRecurId();
if (rid.getDt() != null && rid.getDt().hasZeroTime()) {
CalendarItem calItem = getCalendarItemByUid(octxt, inv.getUid());
if (calItem != null) {
Invite seriesInv = calItem.getDefaultInviteOrNull();
if (seriesInv != null) {
ParsedDateTime seriesDtStart = seriesInv.getStartTime();
if (seriesDtStart != null) {
ParsedDateTime fixedDt = seriesDtStart.cloneWithNewDate(rid.getDt());
RecurId fixedRid = new RecurId(fixedDt, rid.getRange());
ZimbraLog.calendar.debug("Fixed up invalid RECURRENCE-ID with zero time; before=[%s], after=[%s]", rid, fixedRid);
inv.setRecurId(fixedRid);
}
}
}
}
}
processICalReply(octxt, inv, sender);
} else {
Account orgAccount = inv.getOrganizerAccount();
// Unknown organizer
if (orgAccount == null) {
ZimbraLog.calendar.warn("Unknown organizer " + orgAddress + " in REPLY");
continue;
}
if (Provisioning.onLocalServer(orgAccount)) {
// Run in the context of organizer's mailbox.
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(orgAccount);
OperationContext orgOctxt = new OperationContext(mbox);
mbox.processICalReply(orgOctxt, inv, sender);
} else {
// Organizer's mailbox is on a remote server.
String uri = AccountUtil.getSoapUri(orgAccount);
if (uri == null) {
ZimbraLog.calendar.warn("Unable to determine URI for organizer account %s", orgAddress);
continue;
}
try {
// TODO: Get the iCalendar data from the
// MIME part since we already have it.
String ical;
StringWriter sr = null;
try {
sr = new StringWriter();
inv.setMethod(ICalTok.REPLY.toString());
inv.newToICalendar(true).toICalendar(sr);
ical = sr.toString();
} finally {
if (sr != null) {
sr.close();
}
}
Options options = new Options();
AuthToken authToken = AuthToken.getCsrfUnsecuredAuthToken(getAuthToken(octxt));
options.setAuthToken(authToken.toZAuthToken());
options.setTargetAccount(orgAccount.getName());
options.setTargetAccountBy(AccountBy.name);
options.setUri(uri);
options.setNoSession(true);
ZMailbox zmbox = ZMailbox.getMailbox(options);
zmbox.iCalReply(ical, sender);
} catch (IOException e) {
throw ServiceException.FAILURE("Error while posting REPLY to organizer mailbox host", e);
}
}
}
}
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class ModifyInvitePartStat method redo.
@Override
public void redo() throws Exception {
Mailbox mbox = MailboxManager.getInstance().getMailboxById(getMailboxId());
CalendarItem calItem = mbox.getCalendarItemById(null, mCalItemId);
RecurId recurId = null;
if (mRecurIdDt != null)
recurId = new RecurId(ParsedDateTime.parse(mRecurIdDt, calItem.getTimeZoneMap()), mRecurIdRange);
mbox.modifyPartStat(getOperationContext(), mCalItemId, recurId, mCnStr, mAddressStr, mCUTypeStr, mRoleStr, mPartStatStr, mRsvp, mSeqNo, mDtStamp);
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class ToXML method encodeInvitesForMessage.
private static Element encodeInvitesForMessage(Element parent, ItemIdFormatter ifmt, OperationContext octxt, Message msg, int fields, boolean neuter) throws ServiceException {
if (fields != NOTIFY_FIELDS && !needToOutput(fields, Change.INVITE)) {
return parent;
}
Element ie = parent.addNonUniqueElement(MailConstants.E_INVITE);
Mailbox mbox = msg.getMailbox();
for (Iterator<Message.CalendarItemInfo> iter = msg.getCalendarItemInfoIterator(); iter.hasNext(); ) {
Message.CalendarItemInfo info = iter.next();
CalendarItem calItem = null;
ICalTok method = ICalTok.REQUEST;
Invite invCi = info.getInvite();
if (invCi != null) {
method = Invite.lookupMethod(invCi.getMethod());
}
Invite invite = invCi;
ItemId calendarItemId = info.getCalendarItemId();
if (info.calItemCreated()) {
try {
calItem = mbox.getCalendarItemById(octxt, calendarItemId);
} catch (MailServiceException.NoSuchItemException e) {
// Calendar item has been deleted. Bug 84877 - don't include stale references to it in SOAP response
calendarItemId = null;
} catch (ServiceException e) {
// eat PERM_DENIED
if (e.getCode() != ServiceException.PERM_DENIED) {
throw e;
}
// If we can't access it. Don't include a reference to it.
calendarItemId = null;
}
// Do staleness check for invitation messages.
if (ICalTok.REQUEST.equals(method) || ICalTok.PUBLISH.equals(method)) {
if (calItem != null && calItem.getFolderId() != Mailbox.ID_FOLDER_TRASH) {
if (invCi != null) {
// See if the messsage's invite is outdated.
Invite invCurr = calItem.getInvite(invCi.getRecurId());
if (invCurr != null) {
if (invCi.getSeqNo() >= invCurr.getSeqNo()) {
// Invite is new or same as what's in the appointment. Show it.
invite = invCi;
} else {
// Outdated. Don't show it.
invite = null;
}
} else {
// New invite. Show it.
invite = invCi;
}
} else {
// legacy case
invite = calItem.getInvite(msg.getId(), info.getComponentNo());
// invite == null if the invite was outdated by a newer update
}
}
}
} else {
// We have an invite that wasn't auto-added.
if (invCi != null) {
if (!Invite.isOrganizerMethod(invCi.getMethod()) || ICalTok.DECLINECOUNTER.equals(method)) {
invite = invCi;
} else {
try {
calItem = mbox.getCalendarItemByUid(octxt, invCi.getUid());
} catch (MailServiceException.NoSuchItemException e) {
// ignore
} catch (ServiceException e) {
// eat PERM_DENIED
if (e.getCode() != ServiceException.PERM_DENIED) {
throw e;
}
}
if (calItem != null) {
// See if the messsage's invite is outdated.
Invite invCurr = calItem.getInvite(invCi.getRecurId());
if (invCurr != null) {
if (invCi.getSeqNo() >= invCurr.getSeqNo()) {
// Invite is new or same as what's in the appointment. Show it.
invite = invCi;
} else {
// Outdated. Don't show it.
invite = null;
}
} else {
// New invite. Show it.
invite = invCi;
}
} else {
// Appointment doesn't exist. The invite in the message should be displayed and the
// user can manually add the appointment.
invite = invCi;
}
}
}
}
if (invite != null) {
setCalendarItemType(ie, invite.getItemType());
encodeTimeZoneMap(ie, invite.getTimeZoneMap());
com.zimbra.soap.mail.type.CalendarItemInfo remoteCalendarItem = null;
if (calItem == null) {
remoteCalendarItem = msg.getRemoteCalendarItem(invite);
if (remoteCalendarItem != null) {
calendarItemId = new ItemId(remoteCalendarItem.getId(), (String) null);
}
}
encodeInviteComponent(ie, ifmt, octxt, calItem, calendarItemId, invite, fields, neuter);
ICalTok invMethod = Invite.lookupMethod(invite.getMethod());
if (ICalTok.REQUEST.equals(invMethod) || ICalTok.PUBLISH.equals(invMethod)) {
InviteChanges invChanges = info.getInviteChanges();
if (invChanges != null && !invChanges.noChange()) {
Element comp = ie.getOptionalElement(MailConstants.E_INVITE_COMPONENT);
if (comp != null) {
comp.addAttribute(MailConstants.A_CAL_CHANGES, invChanges.toString());
}
}
if (calItem != null) {
boolean showAll = invite.isPublic() || allowPrivateAccess(octxt, calItem);
if (showAll) {
RecurId rid = invite.getRecurId();
encodeCalendarReplies(ie, calItem, invite, rid != null ? rid.getDtZ() : null);
}
} else if (null != remoteCalendarItem) {
CalendarReply.encodeCalendarReplyList(ie, remoteCalendarItem.getCalendarReplies());
}
}
}
}
return ie;
}
Aggregations