use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class ForwardCalendarItem method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Account senderAcct = getZDesktopSafeAuthenticatedAccount(zsc);
Mailbox mbox = getRequestedMailbox(zsc);
OperationContext octxt = getOperationContext(zsc, context);
// proxy handling
ItemId iid = new ItemId(request.getAttribute(MailConstants.A_ID), zsc);
if (!iid.belongsTo(getRequestedAccount(zsc))) {
// Proxy it.
return proxyRequest(request, context, iid.getAccountId());
}
Element msgElem = request.getElement(MailConstants.E_MSG);
ParseMimeMessage.MimeMessageData parsedMessageData = new ParseMimeMessage.MimeMessageData();
MimeMessage mm = ParseMimeMessage.parseMimeMsgSoap(zsc, octxt, mbox, msgElem, null, ParseMimeMessage.NO_INV_ALLOWED_PARSER, parsedMessageData);
Element exc = request.getOptionalElement(MailConstants.E_CAL_EXCEPTION_ID);
Element tzElem = request.getOptionalElement(MailConstants.E_CAL_TZ);
CalendarItem calItem = mbox.getCalendarItemById(octxt, iid.getId());
if (calItem == null) {
throw MailServiceException.NO_SUCH_CALITEM(iid.toString(), "Could not find calendar item");
}
RecurId rid = null;
if (exc != null) {
TimeZoneMap tzmap = calItem.getTimeZoneMap();
ICalTimeZone tz = null;
if (tzElem != null) {
tz = CalendarUtils.parseTzElement(tzElem);
tzmap.add(tz);
}
ParsedDateTime exceptDt = CalendarUtils.parseDateTime(exc, tzmap);
rid = new RecurId(exceptDt, RecurId.RANGE_NONE);
}
Pair<List<MimeMessage>, List<MimeMessage>> mimePair = forwardCalItem(mbox, octxt, calItem, rid, mm, senderAcct);
sendForwardMessages(mbox, octxt, mimePair);
Element response = getResponseElement(zsc);
return response;
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class ExpandRecur method parseRecur.
protected static ParsedRecurrence parseRecur(Element request, TimeZoneMap tzmap) throws ServiceException {
CalendarUtils.parseTimeZones(request, tzmap);
IRecurrence recurrence = null;
List<IException> exceptions = new ArrayList<IException>();
for (Iterator<Element> compIter = request.elementIterator(); compIter.hasNext(); ) {
Element elem = compIter.next();
String elemName = elem.getName();
boolean isCancel = false;
if (MailConstants.E_CAL_CANCEL.equals(elemName)) {
isCancel = true;
} else if (!MailConstants.E_INVITE_COMPONENT.equals(elemName) && !MailConstants.E_CAL_EXCEPT.equals(elemName)) {
continue;
}
RecurId recurId = null;
Element recurIdElem = elem.getOptionalElement(MailConstants.E_CAL_EXCEPTION_ID);
if (recurIdElem != null)
recurId = CalendarUtils.parseRecurId(recurIdElem, tzmap);
if (!isCancel) {
ParsedDateTime dtStart = null;
Element dtStartElem = elem.getElement(MailConstants.E_CAL_START_TIME);
dtStart = CalendarUtils.parseDateTime(dtStartElem, tzmap);
ParsedDateTime dtEnd = null;
Element dtEndElem = elem.getOptionalElement(MailConstants.E_CAL_END_TIME);
if (dtEndElem != null)
dtEnd = CalendarUtils.parseDateTime(dtEndElem, tzmap);
ParsedDuration dur = null;
Element durElem = elem.getOptionalElement(MailConstants.E_CAL_DURATION);
if (durElem != null)
dur = ParsedDuration.parse(durElem);
if (dtEnd == null && dur == null)
throw ServiceException.INVALID_REQUEST("Must specify either " + MailConstants.E_CAL_END_TIME + " or " + MailConstants.E_CAL_DURATION + " in " + elemName, null);
Element recurElem = elem.getOptionalElement(MailConstants.E_CAL_RECUR);
if (recurElem != null) {
// series with a rule
recurrence = CalendarUtils.parseRecur(recurElem, tzmap, dtStart, dtEnd, dur, recurId);
} else {
// modified instance, or it has no rule and no recurrence-id
if (dur == null && dtStart != null && dtEnd != null)
dur = dtEnd.difference(dtStart);
if (recurId == null)
recurId = new RecurId(dtStart, RecurId.RANGE_NONE);
exceptions.add(new ExceptionRule(recurId, dtStart, dur, null));
}
} else if (recurId != null) {
// canceled instance
exceptions.add(new CancellationRule(recurId));
}
}
ParsedRecurrence parsed = new ParsedRecurrence();
if (recurrence instanceof RecurrenceRule) {
RecurrenceRule rrule = (RecurrenceRule) recurrence;
for (IException exception : exceptions) {
rrule.addException(exception);
}
parsed.rrule = rrule;
} else {
parsed.exceptions = exceptions;
}
return parsed;
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class Message method processInvitesAfterCreate.
/**
* This has to be done as a separate step, after the MailItem has been added, because of foreign key constraints on
* the CalendarItems table.
*/
private void processInvitesAfterCreate(String method, int folderId, boolean applyToCalendar, ParsedMessage pm, List<Invite> invites) throws ServiceException {
if (pm == null) {
throw ServiceException.INVALID_REQUEST("null ParsedMessage while processing invite in message " + mId, null);
}
Account acct = getAccount();
AccountAddressMatcher acctMatcher = new AccountAddressMatcher(acct);
OperationContext octxt = getMailbox().getOperationContext();
ProcessInvitesStatus status = new ProcessInvitesStatus(acct, pm);
status.initAutoAddNew(octxt);
boolean isOrganizerMethod = Invite.isOrganizerMethod(method);
if (isOrganizerMethod && !invites.isEmpty() && status.intendedForMe) {
// Check if the sender is allowed to invite this user. Only do this for invite-type methods,
// namely REQUEST/PUBLISH/CANCEL/ADD/DECLINECOUNTER. REPLY/REFRESH/COUNTER don't undergo
// the check because they are not organizer-to-attendee methods.
String senderEmail;
Account senderAcct = null;
boolean onBehalfOf = false;
boolean canInvite;
AccessManager accessMgr = AccessManager.getInstance();
if (octxt != null && octxt.getAuthenticatedUser() != null) {
onBehalfOf = octxt.isDelegatedRequest(getMailbox());
senderAcct = octxt.getAuthenticatedUser();
senderEmail = senderAcct.getName();
canInvite = accessMgr.canDo(senderAcct, acct, User.R_invite, octxt.isUsingAdminPrivileges());
} else {
senderEmail = pm.getSenderEmail(false);
if (senderEmail != null) {
senderAcct = Provisioning.getInstance().get(AccountBy.name, senderEmail);
}
canInvite = accessMgr.canDo(senderEmail, acct, User.R_invite, false);
}
if (!canInvite) {
Invite invite = invites.get(0);
CalendarMailSender.handleInviteAutoDeclinedNotification(octxt, getMailbox(), acct, senderEmail, senderAcct, onBehalfOf, applyToCalendar, getId(), invite);
String inviteSender = senderEmail != null ? senderEmail : "unknown sender";
ZimbraLog.calendar.info("Calendar invite from %s to %s is not allowed", inviteSender, acct.getName());
// Turn off auto-add. We still have to run through the code below to save the invite's
// data in message's metadata.
status.autoAddNew = false;
}
}
// Override CLASS property if preference says to mark everything as private.
PrefCalendarApptVisibility prefClass = acct.getPrefCalendarApptVisibility();
boolean forcePrivateClass = prefClass != null && !prefClass.equals(PrefCalendarApptVisibility.public_);
// Ignore alarms set by organizer.
boolean allowOrganizerAlarm = DebugConfig.calendarAllowOrganizerSpecifiedAlarms;
if (calendarItemInfos == null) {
calendarItemInfos = new ArrayList<CalendarItemInfo>();
}
// properties.
if (invites.size() > 1) {
boolean hasSeries = false;
ZOrganizer seriesOrganizer = null;
boolean seriesIsOrganizer = false;
List<ZAttendee> seriesAttendees = null;
ParsedDateTime seriesDtStart = null;
// Get organizer and attendees from series VEVENT.
for (Invite inv : invites) {
if (!inv.hasRecurId()) {
hasSeries = true;
seriesOrganizer = inv.getOrganizer();
seriesIsOrganizer = inv.isOrganizer();
seriesAttendees = inv.getAttendees();
seriesDtStart = inv.getStartTime();
break;
}
}
if (hasSeries) {
for (Invite inv : invites) {
RecurId rid = inv.getRecurId();
if (rid != null) {
if (seriesOrganizer != null && !inv.hasOrganizer()) {
inv.setOrganizer(seriesOrganizer);
inv.setIsOrganizer(seriesIsOrganizer);
// exception instance to have no attendee.
if (!inv.hasOtherAttendees() && seriesAttendees != null) {
for (ZAttendee at : seriesAttendees) {
inv.addAttendee(at);
}
}
}
if (!inv.isAllDayEvent() && seriesDtStart != null) {
// Exchange can send invalid RECURRENCE-ID with HHMMSS set to 000000. Detect it and fix it up
// by copying the time from series DTSTART.
ParsedDateTime ridDt = rid.getDt();
if (ridDt != null && ridDt.hasZeroTime() && !seriesDtStart.hasZeroTime() && ridDt.sameTimeZone(seriesDtStart)) {
ParsedDateTime fixedDt = seriesDtStart.cloneWithNewDate(ridDt);
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);
}
}
// Exception instance invites shouldn't point to the same MIME part in the appointment blob
// as the series invite. If they do, we will lose the series attachment when a new exception
// instance update is received.
inv.setMailItemId(0);
}
}
}
}
// used to check if any invite is non-public
boolean publicInvites = true;
status.calItemFolderId = invites.size() > 0 && invites.get(0).isTodo() ? Mailbox.ID_FOLDER_TASKS : Mailbox.ID_FOLDER_CALENDAR;
CalendarItem firstCalItem = null;
Set<String> calUidsSeen = new HashSet<String>();
for (Invite cur : invites) {
if (!cur.isPublic()) {
publicInvites = false;
}
// it's the correct organizer.
if (!cur.hasOrganizer() && cur.hasOtherAttendees()) {
String fromEmail = pm.getSenderEmail(true);
if (fromEmail != null) {
boolean dangerousSender = false;
// Is sender == recipient? If so, clear attendees.
if (status.intendedForAddress != null) {
if (status.intendedForAddress.equalsIgnoreCase(fromEmail)) {
ZimbraLog.calendar.info("Got malformed invite without organizer. Clearing attendees to prevent inadvertent cancels.");
cur.clearAttendees();
dangerousSender = true;
}
} else if (acctMatcher.matches(fromEmail)) {
ZimbraLog.calendar.info("Got malformed invite without organizer. Clearing attendees to prevent inadvertent cancels.");
cur.clearAttendees();
dangerousSender = true;
}
if (!dangerousSender) {
if (isOrganizerMethod = Invite.isOrganizerMethod(method)) {
// For organizer-originated methods, use email sender as default organizer.
ZOrganizer org = new ZOrganizer(fromEmail, null);
String senderEmail = pm.getSenderEmail(false);
if (senderEmail != null && !senderEmail.equalsIgnoreCase(fromEmail))
org.setSentBy(senderEmail);
cur.setOrganizer(org);
ZimbraLog.calendar.info("Got malformed invite that lists attendees without specifying an organizer. " + "Defaulting organizer to: " + org.toString());
} else {
// For attendee-originated methods, look up organizer from appointment on calendar.
// If appointment is not found, fall back to the intended-for address, then finally to self.
ZOrganizer org = null;
CalendarItem ci = mMailbox.getCalendarItemByUid(octxt, cur.getUid());
if (ci != null) {
Invite inv = ci.getInvite(cur.getRecurId());
if (inv == null) {
inv = ci.getDefaultInviteOrNull();
}
if (inv != null) {
org = inv.getOrganizer();
}
}
if (org == null) {
if (status.intendedForAddress != null) {
org = new ZOrganizer(status.intendedForAddress, null);
} else {
org = new ZOrganizer(acct.getName(), null);
}
}
cur.setOrganizer(org);
cur.setIsOrganizer(status.intendedForMe);
ZimbraLog.calendar.info("Got malformed reply missing organizer. Defaulting to " + org.toString());
}
}
}
}
cur.setLocalOnly(false);
status.initAddRevisionSetting(cur.getUid(), calUidsSeen);
// other than BUSY. And don't allow transparent meetings. This will prevent double booking in the future.
if (cur.isEvent() && (acct instanceof CalendarResource)) {
cur.setFreeBusy(IcalXmlStrMap.FBTYPE_BUSY);
cur.setTransparency(IcalXmlStrMap.TRANSP_OPAQUE);
}
if (forcePrivateClass) {
cur.setClassProp(IcalXmlStrMap.CLASS_PRIVATE);
cur.setClassPropSetByMe(true);
}
ICalTok methodTok = Invite.lookupMethod(method);
// Discard alarms set by organizer. Add a new one based on attendee's preferences.
if (!allowOrganizerAlarm) {
// only for non-cancel/non-declinecounter VEVENTs
if (cur.isEvent() && isOrganizerMethod && !cur.isCancel() && !ICalTok.DECLINECOUNTER.equals(methodTok))
Invite.setDefaultAlarm(cur, acct);
}
getInfoForAssociatedCalendarItem(acct, cur, method, pm, applyToCalendar, status);
if (firstCalItem == null) {
firstCalItem = status.calItem;
}
}
if (status.updatedMetadata) {
saveMetadata();
}
// Don't forward from a system account. (e.g. archiving, galsync, ham/spam)
if (applyToCalendar && !status.isForwardedInvite && status.intendedForMe && folderId != Mailbox.ID_FOLDER_SENT && !invites.isEmpty() && !acct.isIsSystemResource()) {
// Don't do the forwarding during redo playback.
RedoableOp redoPlayer = octxt != null ? octxt.getPlayer() : null;
RedoLogProvider redoProvider = RedoLogProvider.getInstance();
boolean needToForward = redoProvider.isMaster() && (redoPlayer == null || redoProvider.getRedoLogManager().getInCrashRecovery());
if (needToForward) {
String[] forwardTo = null;
if (isOrganizerMethod) {
forwardTo = acct.getPrefCalendarForwardInvitesTo();
} else {
// not the users listed in the zimbraPrefCalendarForwardInvitesTo preference.
if (firstCalItem != null) {
Invite invCalItem = firstCalItem.getInvite(invites.get(0).getRecurId());
if (invCalItem == null)
invCalItem = firstCalItem.getDefaultInviteOrNull();
if (invCalItem != null && invCalItem.isOrganizer()) {
ZOrganizer org = invCalItem.getOrganizer();
if (org.hasSentBy()) {
forwardTo = new String[] { org.getSentBy() };
}
}
}
}
Account senderAcct = null;
String senderEmail = pm.getSenderEmail(false);
if (senderEmail != null)
senderAcct = Provisioning.getInstance().get(AccountBy.name, senderEmail);
if (forwardTo != null && forwardTo.length > 0) {
// recipients to receive unfiltered message
List<String> rcptsUnfiltered = new ArrayList<String>();
// recipients to receive message filtered to remove private data
List<String> rcptsFiltered = new ArrayList<String>();
Folder calFolder = null;
try {
calFolder = getMailbox().getFolderById(status.calItemFolderId);
} catch (NoSuchItemException e) {
ZimbraLog.mailbox.warn("No such calendar folder (" + status.calItemFolderId + ") during invite auto-forwarding");
}
for (String fwd : forwardTo) {
if (fwd != null) {
fwd = fwd.trim();
}
if (StringUtil.isNullOrEmpty(fwd)) {
continue;
}
// Prevent forwarding to self.
if (acctMatcher.matches(fwd))
continue;
// Don't forward back to the sender. It's redundant and confusing.
Account rcptAcct = Provisioning.getInstance().get(AccountBy.name, fwd);
boolean rcptIsSender = false;
if (rcptAcct != null) {
if (senderAcct != null) {
rcptIsSender = rcptAcct.getId().equalsIgnoreCase(senderAcct.getId());
} else {
rcptIsSender = AccountUtil.addressMatchesAccount(rcptAcct, senderEmail);
}
} else {
if (senderAcct != null) {
rcptIsSender = AccountUtil.addressMatchesAccount(senderAcct, fwd);
} else {
rcptIsSender = fwd.equalsIgnoreCase(senderEmail);
}
}
if (rcptIsSender) {
ZimbraLog.calendar.info("Not auto-forwarding to " + fwd + " because it is the sender of this message");
continue;
}
if (publicInvites) {
rcptsUnfiltered.add(fwd);
} else {
boolean allowed = false;
if (calFolder != null && rcptAcct != null) {
allowed = calFolder.canAccess(ACL.RIGHT_PRIVATE, rcptAcct, false);
}
if (allowed) {
rcptsUnfiltered.add(fwd);
} else if (acct instanceof CalendarResource) {
// Forward filtered invite from calendar resource accounts only. Don't forward filtered
// invite from regular user account because the forwardee won't be able to accept/decline
// due to permission error.
rcptsFiltered.add(fwd);
}
}
}
if (!rcptsUnfiltered.isEmpty() || !rcptsFiltered.isEmpty()) {
MimeMessage mmOrig = pm.getMimeMessage();
if (mmOrig != null) {
String origSender = pm.getSenderEmail(false);
String forwarder = AccountUtil.getCanonicalAddress(acct);
if (!rcptsUnfiltered.isEmpty()) {
MimeMessage mm = CalendarMailSender.createForwardedInviteMessage(mmOrig, origSender, forwarder, rcptsUnfiltered.toArray(new String[0]));
if (mm != null) {
ItemId origMsgId = new ItemId(getMailbox(), getId());
CalendarMailSender.sendInviteAutoForwardMessage(octxt, getMailbox(), origMsgId, mm);
}
}
if (!rcptsFiltered.isEmpty()) {
MimeMessage mm = CalendarMailSender.createForwardedPrivateInviteMessage(acct, acct.getLocale(), method, invites, origSender, forwarder, rcptsFiltered.toArray(new String[0]));
if (mm != null) {
ItemId origMsgId = new ItemId(getMailbox(), getId());
CalendarMailSender.sendInviteAutoForwardMessage(octxt, getMailbox(), origMsgId, mm);
}
}
}
}
}
}
}
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class GetMsg method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Mailbox mbox = getRequestedMailbox(zsc);
OperationContext octxt = getOperationContext(zsc, context);
ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
Element eMsg = request.getElement(MailConstants.E_MSG);
ItemId iid = new ItemId(eMsg.getAttribute(MailConstants.A_ID), zsc);
String part = eMsg.getAttribute(MailConstants.A_PART, null);
MsgContent wantContent = MsgContent.fromString(eMsg.getAttribute(MailConstants.A_WANT_CONTENT, null));
wantContent = wantContent == null ? MsgContent.full : wantContent;
boolean raw = eMsg.getAttributeBool(MailConstants.A_RAW, false);
boolean read = eMsg.getAttributeBool(MailConstants.A_MARK_READ, false);
int maxSize = (int) eMsg.getAttributeLong(MailConstants.A_MAX_INLINED_LENGTH, 0);
boolean wantHTML = eMsg.getAttributeBool(MailConstants.A_WANT_HTML, false);
boolean neuter = eMsg.getAttributeBool(MailConstants.A_NEUTER, true);
Set<String> headers = null;
for (Element eHdr : eMsg.listElements(MailConstants.A_HEADER)) {
if (headers == null)
headers = new HashSet<String>();
headers.add(eHdr.getAttribute(MailConstants.A_ATTRIBUTE_NAME));
}
boolean needGroupInfo = eMsg.getAttributeBool(MailConstants.A_NEED_EXP, false);
Element response = zsc.createElement(MailConstants.GET_MSG_RESPONSE);
if (iid.hasSubpart()) {
// calendar item
CalendarItem calItem = getCalendarItem(octxt, mbox, iid);
if (raw) {
throw ServiceException.INVALID_REQUEST("Cannot request RAW formatted subpart message", null);
} else {
String recurIdZ = eMsg.getAttribute(MailConstants.A_CAL_RECURRENCE_ID_Z, null);
if (recurIdZ == null) {
// If not specified, try to get it from the Invite.
int invId = iid.getSubpartId();
Invite[] invs = calItem.getInvites(invId);
if (invs.length > 0) {
RecurId rid = invs[0].getRecurId();
if (rid != null)
recurIdZ = rid.getDtZ();
}
}
ToXML.encodeInviteAsMP(response, ifmt, octxt, calItem, recurIdZ, iid, part, maxSize, wantHTML, neuter, headers, false, needGroupInfo);
}
} else {
Message msg = getMsg(octxt, mbox, iid, read);
if (raw) {
ToXML.encodeMessageAsMIME(response, ifmt, octxt, msg, part, false);
} else {
ToXML.encodeMessageAsMP(response, ifmt, octxt, msg, part, maxSize, wantHTML, neuter, headers, false, needGroupInfo, LC.mime_encode_missing_blob.booleanValue(), wantContent);
}
}
return response;
}
use of com.zimbra.cs.mailbox.calendar.RecurId in project zm-mailbox by Zimbra.
the class GetCalendarItemSummaries method encodeCalendarItemInstances.
/**
* Encodes a calendar item
*
* @param parent
* @param elementName
* name of element to add (MailConstants .E_APPOINTMENT or MailConstants.E_TASK)
* @param rangeStart
* start period to expand instances (or -1 for no start time constraint)
* @param rangeEnd
* end period to expand instances (or -1 for no end time constraint)
* @param newFormat
* temporary HACK - true: SearchRequest, false: GetAppointmentSummaries
* @return
*/
static EncodeCalendarItemResult encodeCalendarItemInstances(ZimbraSoapContext lc, OperationContext octxt, CalendarItem calItem, Account acct, long rangeStart, long rangeEnd, boolean newFormat) throws ServiceException {
EncodeCalendarItemResult toRet = new EncodeCalendarItemResult();
ItemIdFormatter ifmt = new ItemIdFormatter(lc);
Account authAccount = getAuthenticatedAccount(lc);
boolean hidePrivate = !calItem.allowPrivateAccess(authAccount, lc.isUsingAdminPrivileges());
try {
boolean expandRanges;
if (calItem instanceof Task) {
expandRanges = true;
if (rangeStart == -1 && rangeEnd == -1) {
rangeStart = Long.MIN_VALUE;
rangeEnd = Long.MAX_VALUE;
}
} else {
expandRanges = (rangeStart != -1 && rangeEnd != -1 && rangeStart < rangeEnd);
}
boolean isAppointment = calItem instanceof Appointment;
// Use the marshalling code in calendar summary cache for uniform output, when we can.
if (isAppointment && expandRanges) {
CalendarItemData calItemData = CalSummaryCache.reloadCalendarItemOverRange(calItem, rangeStart, rangeEnd);
if (calItemData != null) {
int numInstances = calItemData.getNumInstances();
if (numInstances > 0) {
Element calItemElem = CacheToXML.encodeCalendarItemData(lc, ifmt, calItemData, !hidePrivate, !newFormat);
toRet.element = calItemElem;
toRet.numInstancesExpanded = numInstances;
}
}
return toRet;
}
// But there are other cases (e.g. tasks, no time range) that require the legacy code below.
// don't initialize until we find at least one valid instance
Element calItemElem = null;
Invite defaultInvite = calItem.getDefaultInviteOrNull();
if (defaultInvite == null) {
mLog.info("Could not load defaultinfo for calendar item with id=" + calItem.getId() + " SKIPPING");
return toRet;
}
ParsedDuration defDuration = defaultInvite.getEffectiveDuration();
// events and 1 second for non all-day. (bug 28615)
if (defDuration == null && !defaultInvite.isTodo()) {
if (defaultInvite.isAllDayEvent()) {
defDuration = ParsedDuration.ONE_DAY;
} else {
defDuration = ParsedDuration.ONE_SECOND;
}
}
long defDurationMsecs = 0;
if (defaultInvite.getStartTime() != null && defDuration != null) {
ParsedDateTime s = defaultInvite.getStartTime();
long et = s.add(defDuration).getUtcTime();
defDurationMsecs = et - s.getUtcTime();
}
String defaultFba = null;
if (calItem instanceof Appointment) {
defaultFba = ((Appointment) calItem).getEffectiveFreeBusyActual(defaultInvite, null);
}
String defaultPtSt = calItem.getEffectivePartStat(defaultInvite, null);
AlarmData alarmData = calItem.getAlarmData();
// add all the instances:
int numInRange = 0;
if (expandRanges) {
Collection<CalendarItem.Instance> instances = calItem.expandInstances(rangeStart, rangeEnd, true);
long alarmTime = 0;
long alarmInst = 0;
if (alarmData != null) {
alarmTime = alarmData.getNextAt();
alarmInst = alarmData.getNextInstanceStart();
}
for (CalendarItem.Instance inst : instances) {
try {
InviteInfo invId = inst.getInviteInfo();
Invite inv = calItem.getInvite(invId.getMsgId(), invId.getComponentId());
boolean showAll = !hidePrivate || inv.isPublic();
// figure out which fields are different from the default and put their data here...
ParsedDuration invDuration = inv.getEffectiveDuration();
long instStart = inst.getStart();
// For an instance whose alarm time is within the time range, we must
// include it even if its start time is after the range.
long startOrAlarm = instStart == alarmInst ? alarmTime : instStart;
// events and 1 second for non all-day. (bug 28615)
if (invDuration == null) {
if (inv.isAllDayEvent())
invDuration = ParsedDuration.ONE_DAY;
else
invDuration = ParsedDuration.ONE_SECOND;
}
if (!inst.hasStart() || (startOrAlarm < rangeEnd && invDuration.addToTime(instStart) > rangeStart)) {
numInRange++;
} else {
continue;
}
if (calItemElem == null) {
calItemElem = lc.createElement(isAppointment ? MailConstants.E_APPOINTMENT : MailConstants.E_TASK);
if (showAll) {
// flags and tags
ToXML.recordItemTags(calItemElem, calItem, octxt);
}
// Organizer
if (inv.hasOrganizer()) {
ZOrganizer org = inv.getOrganizer();
org.toXml(calItemElem);
}
calItemElem.addAttribute("x_uid", calItem.getUid());
calItemElem.addAttribute(MailConstants.A_UID, calItem.getUid());
}
Element instElt = calItemElem.addElement(MailConstants.E_INSTANCE);
if (showAll) {
if (isAppointment && inv.isEvent()) {
String instFba = ((Appointment) calItem).getEffectiveFreeBusyActual(inv, inst);
if (instFba != null && (!instFba.equals(defaultFba) || inst.isException()))
instElt.addAttribute(MailConstants.A_APPT_FREEBUSY_ACTUAL, instFba);
}
String instPtSt = calItem.getEffectivePartStat(inv, inst);
if (!defaultPtSt.equals(instPtSt) || inst.isException())
instElt.addAttribute(MailConstants.A_CAL_PARTSTAT, instPtSt);
}
if (inst.hasStart()) {
instElt.addAttribute(MailConstants.A_CAL_START_TIME, instStart);
if (inv.isAllDayEvent())
instElt.addAttribute(MailConstants.A_CAL_TZ_OFFSET, inst.getStartTzOffset());
}
if (inst.isException() && inv.hasRecurId()) {
RecurId rid = inv.getRecurId();
instElt.addAttribute(MailConstants.A_CAL_RECURRENCE_ID_Z, rid.getDtZ());
} else {
instElt.addAttribute(MailConstants.A_CAL_RECURRENCE_ID_Z, inst.getRecurIdZ());
}
if (inst.isException()) {
instElt.addAttribute(MailConstants.A_CAL_IS_EXCEPTION, true);
instElt.addAttribute(MailConstants.A_CAL_INV_ID, ifmt.formatItemId(calItem, inst.getMailItemId()));
instElt.addAttribute(MailConstants.A_CAL_COMPONENT_NUM, inst.getComponentNum());
if (showAll) {
// fragment has already been sanitized...
String frag = inv.getFragment();
if (frag != null && !frag.equals(""))
instElt.addAttribute(MailConstants.E_FRAG, frag, Element.Disposition.CONTENT);
if (inv.getPriority() != null)
instElt.addAttribute(MailConstants.A_CAL_PRIORITY, inv.getPriority());
if (inv.isEvent()) {
if (inv.getFreeBusy() != null)
instElt.addAttribute(MailConstants.A_APPT_FREEBUSY, inv.getFreeBusy());
if (inv.getTransparency() != null)
instElt.addAttribute(MailConstants.A_APPT_TRANSPARENCY, inv.getTransparency());
}
if (inv.isTodo()) {
if (inv.getPercentComplete() != null)
instElt.addAttribute(MailConstants.A_TASK_PERCENT_COMPLETE, inv.getPercentComplete());
}
if (inv.getName() != null)
instElt.addAttribute(MailConstants.A_NAME, inv.getName());
if (inv.getLocation() != null)
instElt.addAttribute(MailConstants.A_CAL_LOCATION, inv.getLocation());
List<String> categories = inv.getCategories();
if (categories != null) {
for (String cat : categories) {
instElt.addElement(MailConstants.E_CAL_CATEGORY).setText(cat);
}
}
Geo geo = inv.getGeo();
if (geo != null)
geo.toXml(instElt);
if (inv.hasOtherAttendees())
instElt.addAttribute(MailConstants.A_CAL_OTHER_ATTENDEES, true);
if (inv.hasAlarm())
instElt.addAttribute(MailConstants.A_CAL_ALARM, true);
}
instElt.addAttribute(MailConstants.A_CAL_ISORG, inv.isOrganizer());
if (inv.isTodo()) {
if (inst.hasEnd()) {
instElt.addAttribute(MailConstants.A_TASK_DUE_DATE, inst.getEnd());
if (inv.isAllDayEvent())
instElt.addAttribute(MailConstants.A_CAL_TZ_OFFSET_DUE, inst.getEndTzOffset());
}
} else {
if (inst.hasStart() && inst.hasEnd()) {
instElt.addAttribute(newFormat ? MailConstants.A_CAL_NEW_DURATION : MailConstants.A_CAL_DURATION, inst.getEnd() - inst.getStart());
}
}
if (inv.getStatus() != null)
instElt.addAttribute(MailConstants.A_CAL_STATUS, inv.getStatus());
if (inv.getClassProp() != null)
instElt.addAttribute(MailConstants.A_CAL_CLASS, inv.getClassProp());
if (inv.isAllDayEvent())
instElt.addAttribute(MailConstants.A_CAL_ALLDAY, true);
if (inv.isDraft())
instElt.addAttribute(MailConstants.A_CAL_DRAFT, true);
if (inv.isNeverSent())
instElt.addAttribute(MailConstants.A_CAL_NEVER_SENT, true);
if (inv.isRecurrence())
instElt.addAttribute(MailConstants.A_CAL_RECUR, true);
} else {
if (inv.isTodo()) {
if (inst.hasEnd()) {
instElt.addAttribute(MailConstants.A_TASK_DUE_DATE, inst.getEnd());
if (inv.isAllDayEvent())
instElt.addAttribute(MailConstants.A_CAL_TZ_OFFSET_DUE, inst.getEndTzOffset());
}
} else {
// the default duration due to daylight savings time transitions.
if (inst.hasStart() && inst.hasEnd() && defDurationMsecs != inst.getEnd() - inst.getStart()) {
instElt.addAttribute(newFormat ? MailConstants.A_CAL_NEW_DURATION : MailConstants.A_CAL_DURATION, inst.getEnd() - inst.getStart());
}
}
}
} catch (MailServiceException.NoSuchItemException e) {
mLog.info("Error could not get instance " + inst.getMailItemId() + "-" + inst.getComponentNum() + " for appt " + calItem.getId(), e);
}
}
// iterate all the instances
}
if (!expandRanges || numInRange > 0) {
// if we found any calItems at all, we have to encode the "Default" data here
boolean showAll = !hidePrivate || defaultInvite.isPublic();
if (calItemElem == null) {
calItemElem = lc.createElement(isAppointment ? MailConstants.E_APPOINTMENT : MailConstants.E_TASK);
calItemElem.addAttribute("x_uid", calItem.getUid());
calItemElem.addAttribute(MailConstants.A_UID, calItem.getUid());
if (showAll) {
// flags and tags
ToXML.recordItemTags(calItemElem, calItem, octxt);
}
// Organizer
if (defaultInvite.hasOrganizer()) {
ZOrganizer org = defaultInvite.getOrganizer();
org.toXml(calItemElem);
}
}
if (showAll) {
if (alarmData != null)
ToXML.encodeAlarmData(calItemElem, calItem, alarmData);
String defaultPriority = defaultInvite.getPriority();
if (defaultPriority != null)
calItemElem.addAttribute(MailConstants.A_CAL_PRIORITY, defaultPriority);
calItemElem.addAttribute(MailConstants.A_CAL_PARTSTAT, defaultPtSt);
if (defaultInvite.isEvent()) {
calItemElem.addAttribute(MailConstants.A_APPT_FREEBUSY, defaultInvite.getFreeBusy());
calItemElem.addAttribute(MailConstants.A_APPT_FREEBUSY_ACTUAL, defaultFba);
calItemElem.addAttribute(MailConstants.A_APPT_TRANSPARENCY, defaultInvite.getTransparency());
}
if (defaultInvite.isTodo()) {
String pctComplete = defaultInvite.getPercentComplete();
if (pctComplete != null)
calItemElem.addAttribute(MailConstants.A_TASK_PERCENT_COMPLETE, pctComplete);
}
calItemElem.addAttribute(MailConstants.A_NAME, defaultInvite.getName());
calItemElem.addAttribute(MailConstants.A_CAL_LOCATION, defaultInvite.getLocation());
List<String> categories = defaultInvite.getCategories();
if (categories != null) {
for (String cat : categories) {
calItemElem.addElement(MailConstants.E_CAL_CATEGORY).setText(cat);
}
}
Geo geo = defaultInvite.getGeo();
if (geo != null)
geo.toXml(calItemElem);
// fragment has already been sanitized...
String fragment = defaultInvite.getFragment();
if (!fragment.equals(""))
calItemElem.addAttribute(MailConstants.E_FRAG, fragment, Element.Disposition.CONTENT);
if (defaultInvite.hasOtherAttendees()) {
calItemElem.addAttribute(MailConstants.A_CAL_OTHER_ATTENDEES, defaultInvite.hasOtherAttendees());
}
if (defaultInvite.hasAlarm()) {
calItemElem.addAttribute(MailConstants.A_CAL_ALARM, defaultInvite.hasAlarm());
}
}
calItemElem.addAttribute(MailConstants.A_CAL_ISORG, defaultInvite.isOrganizer());
calItemElem.addAttribute(MailConstants.A_ID, ifmt.formatItemId(calItem));
calItemElem.addAttribute(MailConstants.A_CAL_INV_ID, ifmt.formatItemId(calItem, defaultInvite.getMailItemId()));
calItemElem.addAttribute(MailConstants.A_CAL_COMPONENT_NUM, defaultInvite.getComponentNum());
calItemElem.addAttribute(MailConstants.A_FOLDER, ifmt.formatItemId(new ItemId(calItem.getMailbox().getAccountId(), calItem.getFolderId())));
calItemElem.addAttribute(MailConstants.A_CAL_STATUS, defaultInvite.getStatus());
calItemElem.addAttribute(MailConstants.A_CAL_CLASS, defaultInvite.getClassProp());
if (!defaultInvite.isTodo())
calItemElem.addAttribute(newFormat ? MailConstants.A_CAL_NEW_DURATION : MailConstants.A_CAL_DURATION, defDurationMsecs);
if (defaultInvite.isAllDayEvent())
calItemElem.addAttribute(MailConstants.A_CAL_ALLDAY, defaultInvite.isAllDayEvent());
if (defaultInvite.isDraft())
calItemElem.addAttribute(MailConstants.A_CAL_DRAFT, defaultInvite.isDraft());
if (defaultInvite.isNeverSent())
calItemElem.addAttribute(MailConstants.A_CAL_NEVER_SENT, defaultInvite.isNeverSent());
if (defaultInvite.isRecurrence())
calItemElem.addAttribute(MailConstants.A_CAL_RECUR, defaultInvite.isRecurrence());
if (calItem.hasExceptions()) {
calItemElem.addAttribute(MailConstants.A_CAL_HAS_EXCEPTIONS, true);
}
toRet.element = calItemElem;
}
toRet.numInstancesExpanded = numInRange;
} catch (MailServiceException.NoSuchItemException e) {
mLog.info("Error could not get default invite for calendar item: " + calItem.getId(), e);
} catch (RuntimeException e) {
mLog.info("Caught Exception " + e + " while getting summary info for calendar item: " + calItem.getId(), e);
}
return toRet;
}
Aggregations