use of com.zimbra.cs.mailbox.calendar.ZOrganizer in project zm-mailbox by Zimbra.
the class SendMsg method doSendMessage.
public static ItemId doSendMessage(OperationContext oc, Mailbox mbox, MimeMessage mm, List<Upload> uploads, ItemId origMsgId, String replyType, String identityId, String dataSourceId, boolean noSaveToSent, boolean needCalendarSentByFixup, boolean isCalendarForward) throws ServiceException {
boolean isCalendarMessage = false;
ItemId id;
OutlookICalendarFixupMimeVisitor mv = null;
if (needCalendarSentByFixup || isCalendarForward) {
mv = new OutlookICalendarFixupMimeVisitor(mbox.getAccount(), mbox).needFixup(needCalendarSentByFixup).setIsCalendarForward(isCalendarForward);
try {
mv.accept(mm);
} catch (MessagingException e) {
throw ServiceException.PARSE_ERROR("Error while fixing up SendMsg for SENT-BY", e);
}
isCalendarMessage = mv.isCalendarMessage();
}
MailSender sender;
if (dataSourceId == null) {
sender = isCalendarMessage ? CalendarMailSender.getCalendarMailSender(mbox) : mbox.getMailSender();
if (noSaveToSent) {
id = sender.sendMimeMessage(oc, mbox, false, mm, uploads, origMsgId, replyType, null, false, processor);
} else {
id = sender.sendMimeMessage(oc, mbox, mm, uploads, origMsgId, replyType, identityId, false, processor);
}
} else {
com.zimbra.cs.account.DataSource dataSource = mbox.getAccount().getDataSourceById(dataSourceId);
if (dataSource == null) {
throw ServiceException.INVALID_REQUEST("No data source with id " + dataSourceId, null);
}
if (!dataSource.isSmtpEnabled()) {
throw ServiceException.INVALID_REQUEST("Data source SMTP is not enabled", null);
}
sender = mbox.getDataSourceMailSender(dataSource, isCalendarMessage);
id = sender.sendDataSourceMimeMessage(oc, mbox, mm, uploads, origMsgId, replyType);
}
// Send Calendar Forward Invitation notification if applicable
try {
if (isCalendarMessage && isCalendarForward && mv.getOriginalInvite() != null) {
ZOrganizer org = mv.getOriginalInvite().getOrganizer();
if (org != null) {
String orgAddress = org.getAddress();
Account orgAccount = Provisioning.getInstance().getAccountByName(orgAddress);
if (orgAccount != null && !orgAccount.getId().equals(mbox.getAccount().getId())) {
MimeMessage notifyMimeMsg = CalendarMailSender.createForwardNotifyMessage(mbox.getAccount(), orgAccount, orgAddress, mm.getAllRecipients(), mv.getOriginalInvite());
CalendarMailSender.sendPartial(oc, mbox, notifyMimeMsg, null, null, null, null, false, true);
}
}
}
} catch (Exception e) {
ZimbraLog.soap.warn("Ignoring error while sending Calendar Invitation Forward Notification", e);
}
return id;
}
use of com.zimbra.cs.mailbox.calendar.ZOrganizer in project zm-mailbox by Zimbra.
the class CalItemSmsReminderTask method getText.
private String getText(CalendarItem calItem, Invite invite, Locale locale, TimeZone tz) throws ServiceException {
DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
dateTimeFormat.setTimeZone(tz);
DateFormat onlyDateFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale);
onlyDateFormat.setTimeZone(tz);
String formattedStart;
String formattedEnd;
if (calItem.getType() == MailItem.Type.APPOINTMENT) {
Date start = new Date(new Long(getProperty(NEXT_INST_START_PROP_NAME)));
formattedStart = dateTimeFormat.format(start);
Date end = invite.getEffectiveDuration().addToDate(start);
formattedEnd = dateTimeFormat.format(end);
} else {
// start date and due date is optional for tasks
formattedStart = invite.getStartTime() == null ? "" : onlyDateFormat.format(invite.getStartTime().getDate());
formattedEnd = invite.getEndTime() == null ? "" : onlyDateFormat.format(invite.getEndTime().getDate());
}
String location = invite.getLocation();
if (StringUtil.isNullOrEmpty(location))
location = L10nUtil.getMessage(L10nUtil.MsgKey.noLocation);
String organizer = null;
ZOrganizer zOrganizer = invite.getOrganizer();
if (zOrganizer != null)
organizer = zOrganizer.hasCn() ? zOrganizer.getCn() : zOrganizer.getAddress();
if (organizer == null)
organizer = "";
String folder = calItem.getMailbox().getFolderById(null, calItem.getFolderId()).getName();
return L10nUtil.getMessage(calItem.getType() == MailItem.Type.APPOINTMENT ? L10nUtil.MsgKey.apptReminderSmsText : L10nUtil.MsgKey.taskReminderSmsText, locale, calItem.getSubject(), formattedStart, formattedEnd, location, organizer, folder);
}
use of com.zimbra.cs.mailbox.calendar.ZOrganizer in project zm-mailbox by Zimbra.
the class GetMsgTest method testHandle.
@Test
public void testHandle() throws Exception {
Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com");
Account acct2 = Provisioning.getInstance().get(Key.AccountBy.name, "test2@zimbra.com");
Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1);
Folder calendarFolder = mbox1.getCalendarFolders(null, SortBy.NONE).get(0);
String fragment = "Some message";
ZVCalendar calendar = new ZVCalendar();
calendar.addDescription(desc, null);
ZComponent comp = new ZComponent("VEVENT");
calendar.addComponent(comp);
Invite invite = MailboxTestUtil.generateInvite(acct1, fragment, calendar);
ICalTimeZone ical = invite.getTimeZoneMap().getLocalTimeZone();
long utc = 5 * 60 * 60 * 1000;
ParsedDateTime s = ParsedDateTime.fromUTCTime(System.currentTimeMillis() + utc, ical);
ParsedDateTime e = ParsedDateTime.fromUTCTime(System.currentTimeMillis() + (30 * 60 * 1000) + utc, ical);
invite.setDtStart(s);
invite.setDtEnd(e);
invite.setPriority("5");
invite.setClassProp("PRI");
invite.setOrganizer(new ZOrganizer("test@zimbra.com", null));
invite.setUid(UUID.randomUUID().toString());
invite.setMethod("REQUEST");
invite.setName("Testing");
invite.setFreeBusy("B");
invite.setIsOrganizer(true);
invite.setItemType(MailItem.Type.APPOINTMENT);
invite.setUid(UUID.randomUUID().toString());
AddInviteData inviteData = mbox1.addInvite(null, invite, calendarFolder.getId());
calendarFolder = mbox1.getCalendarFolders(null, SortBy.NONE).get(0);
Element request = new Element.XMLElement("GetCalendarItem");
Element action = request.addElement(MailConstants.E_MSG);
action.addAttribute(MailConstants.A_ID, acct1.getId() + ":" + inviteData.calItemId + "-" + inviteData.invId);
action.addAttribute(MailConstants.A_WANT_HTML, "1");
action.addAttribute(MailConstants.A_NEED_EXP, "1");
Element response = new GetMsg().handle(request, ServiceTestUtil.getRequestContext(acct1));
Element organizer = response.getElement("m").getElement("inv").getElement("comp").getElement("or");
String organizerString = organizer.prettyPrint();
assertTrue(organizerString.contains("a=\"test@zimbra.com\" url=\"test@zimbra.com\""));
mbox1.grantAccess(null, 10, acct2.getId(), ACL.GRANTEE_USER, ACL.RIGHT_READ, null);
request = new Element.XMLElement("CreateMountPoint");
Element link = request.addElement("link");
link.addAttribute("f", "#");
link.addAttribute("reminder", 0);
link.addAttribute("name", "sharedcal");
link.addAttribute("path", "/Calendar");
link.addAttribute("owner", "test@zimbra.com");
link.addAttribute("l", 10);
link.addAttribute("view", "appoinment");
response = new CreateMountpoint().handle(request, ServiceTestUtil.getRequestContext(acct2));
String mptId = response.getElement("link").getAttribute("id");
request = new Element.XMLElement("GetMsgRequest");
action = request.addElement(MailConstants.E_MSG);
action.addAttribute(MailConstants.A_ID, acct1.getId() + ":" + inviteData.calItemId + "-" + mptId);
action.addAttribute(MailConstants.A_WANT_HTML, "1");
action.addAttribute(MailConstants.A_NEED_EXP, "1");
response = new GetMsg().handle(request, ServiceTestUtil.getRequestContext(acct2, acct1));
organizerString = response.getElement("m").prettyPrint();
assertTrue(!organizerString.contains("a=\"test@zimbra.com\" url=\"test@zimbra.com\""));
request = new Element.XMLElement("FolderAction");
action = request.addElement("action");
action.addAttribute("id", mptId);
action.addAttribute("op", "delete");
response = new FolderAction().handle(request, ServiceTestUtil.getRequestContext(acct2));
mbox1.revokeAccess(null, 10, acct2.getId());
}
use of com.zimbra.cs.mailbox.calendar.ZOrganizer in project zm-mailbox by Zimbra.
the class Message method getInfoForAssociatedCalendarItem.
/**
* Update {@code status.calItem} and {@code calendarItemInfos}
*/
private void getInfoForAssociatedCalendarItem(Account acct, Invite cur, String method, ParsedMessage pm, boolean applyToCalendar, ProcessInvitesStatus status) throws ServiceException {
boolean calItemIsNew = false;
boolean modifiedCalItem = false;
boolean success = false;
try {
InviteChanges invChanges = null;
// Look for organizer-provided change list.
ZProperty changesProp = cur.getXProperty(ICalTok.X_ZIMBRA_CHANGES.toString());
if (changesProp != null) {
invChanges = new InviteChanges(changesProp.getValue());
// Don't let the x-prop propagate further. This x-prop is used during transport only. Presence
// of this x-prop in the appointment object can confuse clients.
cur.removeXProp(ICalTok.X_ZIMBRA_CHANGES.toString());
}
if (!(status.intendedForMe || status.intendedForCalendarIManage)) {
// Not intended for me. Just save the invite detail in metadata.
CalendarItemInfo info = new CalendarItemInfo(CalendarItemInfo.CALITEM_ID_NONE, cur.getComponentNum(), cur, invChanges);
calendarItemInfos.add(info);
status.updatedMetadata = true;
success = true;
return;
}
OperationContext octxt = getMailbox().getOperationContext();
ICalTok methodTok = Invite.lookupMethod(method);
AccountAddressMatcher acctMatcher = status.getAcctMatcher();
cur.sanitize(true);
if (status.intendedForCalendarIManage) {
Provisioning prov = Provisioning.getInstance();
Account ownerAcct = prov.get(AccountBy.name, calendarIntendedFor);
com.zimbra.soap.mail.type.CalendarItemInfo cii = getMailbox().getRemoteCalItemByUID(ownerAcct, cur.getUid(), false, false);
CalendarItemInfo info;
if (cii == null) {
info = new CalendarItemInfo(CalendarItemInfo.CALITEM_ID_NONE, cur.getComponentNum(), cur, invChanges);
calendarItemInfos.add(info);
} else {
int calItemId;
String owner;
try {
ItemId iid = new ItemId(cii.getId(), (String) null);
calItemId = iid.getId();
owner = iid.getAccountId();
} catch (Exception e) {
calItemId = CalendarItemInfo.CALITEM_ID_NONE;
owner = null;
}
info = new CalendarItemInfo(calItemId, owner, cur.getComponentNum(), cur, invChanges);
calendarItemInfos.add(info);
}
status.updatedMetadata = true;
success = true;
return;
}
status.calItem = mMailbox.getCalendarItemByUid(octxt, cur.getUid());
if (applyToCalendar && // replies are handled elsewhere (in Mailbox.addMessage())
!ICalTok.REPLY.equals(methodTok) && !ICalTok.COUNTER.equals(methodTok) && !ICalTok.DECLINECOUNTER.equals(methodTok)) {
if (status.calItem == null) {
// Allow PUBLISH method as well depending on the preference.
if (ICalTok.REQUEST.equals(methodTok) || (ICalTok.PUBLISH.equals(methodTok) && getAccount().getBooleanAttr(Provisioning.A_zimbraPrefCalendarAllowPublishMethodInvite, false))) {
if (status.autoAddNew) {
if (mMailbox.getAccount().sameAccount(cur.getOrganizerAccount())) {
// Bug 100456 ZCO sends out invites before adding a calendar entry. If server adds
// Calendar entry and ZCO sees that before creating its entry, ZCO gets confused.
LOG.info("Mailbox %d Msg %d Don't create ORGANIZER calendar item for Invite %s", getMailboxId(), getId(), method);
} else {
int flags = 0;
// int flags = Flag.BITMASK_INDEXING_DEFERRED;
// mMailbox.incrementIndexDeferredCount(1);
int defaultFolder = cur.isTodo() ? Mailbox.ID_FOLDER_TASKS : Mailbox.ID_FOLDER_CALENDAR;
status.calItem = mMailbox.createCalendarItem(defaultFolder, flags, null, cur.getUid(), pm, cur, null);
calItemIsNew = true;
status.calItemFolderId = status.calItem.getFolderId();
}
}
} else {
LOG.info("Mailbox %d Message %d SKIPPING Invite %s b/c no CalendarItem could be found", getMailboxId(), getId(), method);
}
} else {
// bug 27887: Ignore when calendar request email somehow made a loop back to the
// organizer address. Necessary conditions are:
//
// 1) This mailbox is currently organizer.
// 2) ORGANIZER in the request is this mailbox.
// 3) User/COS preference doesn't explicitly allow it. (bug 29777)
//
// If ORGANIZER in the request is a different user this is an organizer change request,
// which should be allowed to happen.
boolean ignore = false;
Invite defInv = status.calItem.getDefaultInviteOrNull();
if (defInv != null && defInv.isOrganizer()) {
ZOrganizer org = cur.getOrganizer();
String orgAddress = org != null ? org.getAddress() : null;
if (acctMatcher.matches(orgAddress))
ignore = !acct.getBooleanAttr(Provisioning.A_zimbraPrefCalendarAllowCancelEmailToSelf, false);
}
if (ignore) {
ZimbraLog.calendar.info("Ignoring calendar request emailed from organizer to self, " + "possibly in a mail loop involving mailing lists and/or forwards; " + "calItemId=" + status.calItem.getId() + ", msgId=" + getId());
} else {
// the calendar item in the folder it's currently in.
if (status.addRevision)
status.calItem.snapshotRevision(false);
// If updating (but not canceling) an appointment in trash folder,
// use default calendar folder and discard all existing invites.
boolean discardExistingInvites = false;
int calFolderId = status.calItem.getFolderId();
if (!cur.isCancel() && status.calItem.inTrash()) {
discardExistingInvites = true;
if (status.calItem.getType() == MailItem.Type.TASK) {
calFolderId = Mailbox.ID_FOLDER_TASKS;
} else {
calFolderId = Mailbox.ID_FOLDER_CALENDAR;
}
}
// against the current appointment data.
if (invChanges == null && !cur.isCancel()) {
Invite prev = status.calItem.getInvite(cur.getRecurId());
if (prev == null) {
// If incoming invite is a brand-new exception instance, we have to compare
// against the series data, but adjusted to the RECURRENCE-ID of the instance.
Invite series = status.calItem.getInvite(null);
if (series != null)
prev = series.makeInstanceInvite(cur.getRecurId().getDt());
}
if (prev != null)
invChanges = new InviteChanges(prev, cur);
}
modifiedCalItem = status.calItem.processNewInvite(pm, cur, calFolderId, discardExistingInvites);
status.calItemFolderId = calFolderId;
status.calItem.getFolder().updateHighestMODSEQ();
}
}
}
int calItemId = status.calItem != null ? status.calItem.getId() : CalendarItemInfo.CALITEM_ID_NONE;
CalendarItemInfo info = new CalendarItemInfo(calItemId, cur.getComponentNum(), cur, invChanges);
calendarItemInfos.add(info);
status.updatedMetadata = true;
if (status.calItem != null && (calItemIsNew || modifiedCalItem)) {
mMailbox.index.add(status.calItem);
}
success = true;
} finally {
if (!success && status.calItem != null) {
// Error occurred and the calItem in memory may be out of sync with the database.
// Uncache it here, because the error will be ignored by this method's caller.
getMailbox().uncache(status.calItem);
}
}
}
use of com.zimbra.cs.mailbox.calendar.ZOrganizer 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);
}
}
}
}
}
}
}
}
Aggregations