use of com.zimbra.cs.mailbox.MailItem in project zm-mailbox by Zimbra.
the class SendShareNotification method validateRequest.
private Collection<ShareInfoData> validateRequest(ZimbraSoapContext zsc, Map<String, Object> context, OperationContext octxt, Mailbox mbox, Element request) throws ServiceException {
Element eShare = request.getOptionalElement(MailConstants.E_SHARE);
if (eShare != null) {
return Arrays.asList(validateShareRecipient(zsc, context, octxt, mbox, eShare));
}
String action = request.getAttribute(MailConstants.A_ACTION, null);
ArrayList<ShareInfoData> shareInfos = new ArrayList<ShareInfoData>();
SendShareNotificationRequest req = JaxbUtil.elementToJaxb(request);
ItemId iid = new ItemId(req.getItem().getId(), zsc);
MailItem item = mbox.getItemById(octxt, iid.getId(), MailItem.Type.UNKNOWN);
Provisioning prov = Provisioning.getInstance();
Account account = getRequestedAccount(zsc);
if (item instanceof Mountpoint) {
Mountpoint mp = (Mountpoint) item;
account = prov.get(AccountBy.id, mp.getOwnerId());
}
for (EmailAddrInfo email : req.getEmailAddresses()) {
// add the non-existing grantee as type GRANTEE_GUEST for share notification.
// for revoke notifications return the non-existing grantees only
Pair<NamedEntry, String> grantee;
boolean guestGrantee = false;
byte granteeType = ACL.GRANTEE_USER;
String granteeId = null;
String granteeEmail = email.getAddress();
String granteeDisplayName = null;
try {
grantee = getGrantee(zsc, granteeType, granteeId, granteeEmail);
NamedEntry entry = grantee.getFirst();
if (entry instanceof MailTarget) {
Domain domain = prov.getDomain(account);
String granteeDomainName = ((MailTarget) entry).getDomainName();
if (domain.isInternalSharingCrossDomainEnabled() || domain.getName().equals(granteeDomainName) || Sets.newHashSet(domain.getInternalSharingDomain()).contains(granteeDomainName)) {
if (entry instanceof Group) {
granteeType = ACL.GRANTEE_GROUP;
}
granteeId = entry.getId();
granteeDisplayName = grantee.getSecond();
} else {
guestGrantee = true;
}
}
} catch (ServiceException e) {
if (!e.getCode().equals(MailServiceException.NO_SUCH_GRANTEE)) {
throw e;
}
guestGrantee = true;
}
if (guestGrantee) {
granteeType = ACL.GRANTEE_GUEST;
// if guest, granteeId is the same as granteeEmail
granteeId = granteeEmail;
}
shareInfos.add(getShareInfoData(zsc, context, account, octxt, granteeType, granteeEmail, granteeId, granteeDisplayName, item, REVOKE.equals(action)));
}
return shareInfos;
}
use of com.zimbra.cs.mailbox.MailItem in project zm-mailbox by Zimbra.
the class CalDavDataImport method applyRemoteItem.
private MailItem applyRemoteItem(RemoteItem remoteItem, Folder where) throws ServiceException, IOException {
if (!(remoteItem instanceof RemoteCalendarItem)) {
ZimbraLog.datasource.warn("applyRemoteItem: not a calendar item: %s", remoteItem);
return null;
}
RemoteCalendarItem item = (RemoteCalendarItem) remoteItem;
DataSource ds = getDataSource();
DataSourceItem dsItem = DbDataSource.getReverseMapping(ds, item.href);
OperationContext octxt = new OperationContext(mbox);
MailItem mi = null;
boolean isStale = false;
boolean isCreate = false;
if (dsItem.md == null && item.status != Status.deleted) {
dsItem.md = new Metadata();
dsItem.md.put(METADATA_KEY_TYPE, METADATA_TYPE_APPOINTMENT);
}
if (dsItem.itemId == 0) {
isStale = true;
isCreate = true;
} else {
String etag = dsItem.md.get(METADATA_KEY_ETAG, null);
try {
mi = mbox.getItemById(octxt, dsItem.itemId, MailItem.Type.UNKNOWN);
} catch (MailServiceException.NoSuchItemException se) {
ZimbraLog.datasource.warn("applyRemoteItem: calendar item not found: ", remoteItem);
}
if (item.etag == null) {
ZimbraLog.datasource.warn("No Etag returned for item %s", item.href);
isStale = true;
} else if (etag == null) {
ZimbraLog.datasource.warn("Empty etag for item %d", dsItem.itemId);
isStale = true;
} else {
isStale = !item.etag.equals(etag);
}
if (mi == null)
isStale = true;
}
if (item.status == Status.deleted) {
ZimbraLog.datasource.debug("Deleting appointment %s", item.href);
try {
mi = mbox.getItemById(octxt, item.itemId, MailItem.Type.UNKNOWN);
} catch (NoSuchItemException se) {
mi = null;
}
try {
mbox.delete(octxt, item.itemId, MailItem.Type.UNKNOWN);
} catch (ServiceException se) {
ZimbraLog.datasource.warn("Error deleting remotely deleted item %d (%s)", item.itemId, dsItem.remoteId);
}
} else if (isStale) {
ZimbraLog.datasource.debug("Updating stale appointment %s", item.href);
ZCalendar.ZVCalendar vcalendar;
SetCalendarItemData main = new SetCalendarItemData();
SetCalendarItemData[] exceptions = null;
CalDavClient client = null;
try {
client = getClient();
} catch (DavException e) {
throw ServiceException.FAILURE("error creating CalDAV client", e);
}
Appointment appt = client.getCalendarData(new Appointment(item.href, item.etag));
if (appt.data == null) {
ZimbraLog.datasource.warn("No appointment found at " + item.href);
return null;
}
dsItem.md.put(METADATA_KEY_ETAG, appt.etag);
try {
vcalendar = ZCalendar.ZCalendarBuilder.build(appt.data);
List<Invite> invites = Invite.createFromCalendar(mbox.getAccount(), null, vcalendar, true);
if (invites.size() > 1)
exceptions = new SetCalendarItemData[invites.size() - 1];
int pos = 0;
boolean first = true;
for (Invite i : invites) {
if (first) {
main.invite = i;
first = false;
} else {
SetCalendarItemData scid = new SetCalendarItemData();
scid.invite = i;
exceptions[pos++] = scid;
}
}
} catch (Exception e) {
ZimbraLog.datasource.warn("Error parsing appointment ", e);
return null;
}
mi = mbox.setCalendarItem(octxt, where.getId(), 0, null, main, exceptions, null, CalendarItem.NEXT_ALARM_KEEP_CURRENT);
dsItem.itemId = mi.getId();
dsItem.folderId = mi.getFolderId();
if (isCreate) {
DbDataSource.addMapping(ds, dsItem);
} else {
DbDataSource.updateMapping(ds, dsItem);
}
} else {
ZimbraLog.datasource.debug("Appointment up to date %s", item.href);
try {
mi = mbox.getItemById(octxt, dsItem.itemId, MailItem.Type.UNKNOWN);
} catch (NoSuchItemException se) {
// item not found. delete the mapping so it can be downloaded again if needed.
ArrayList<Integer> deletedIds = new ArrayList<Integer>();
deletedIds.add(dsItem.itemId);
DbDataSource.deleteMappings(ds, deletedIds);
}
}
return mi;
}
use of com.zimbra.cs.mailbox.MailItem in project zm-mailbox by Zimbra.
the class CalItemReminderService method notify.
@Override
public void notify(ChangeNotification notification) {
Account account = notification.mailboxAccount;
if (notification.mods.created != null) {
for (Map.Entry<ModificationKey, MailItem> entry : notification.mods.created.entrySet()) {
MailItem item = entry.getValue();
if (item instanceof CalendarItem) {
ZimbraLog.scheduler.debug("Handling creation of calendar item (id=%s,mailboxId=%s)", item.getId(), item.getMailboxId());
scheduleNextReminders((CalendarItem) item, true, true);
}
}
}
if (notification.mods.modified != null) {
for (Map.Entry<ModificationKey, Change> entry : notification.mods.modified.entrySet()) {
Change change = entry.getValue();
if (change.what instanceof CalendarItem) {
CalendarItem calItem = (CalendarItem) change.what;
ZimbraLog.scheduler.debug("Handling modification of calendar item (id=%s,mailboxId=%s)", calItem.getId(), calItem.getMailboxId());
boolean calItemCanceled = false;
try {
if ((change.why & Change.FOLDER) != 0 && calItem.inTrash()) {
calItemCanceled = true;
}
} catch (ServiceException e) {
ZimbraLog.scheduler.error("Error in fetching calendar item's folder", e);
}
// cancel any existing reminders and schedule new ones if cal item not canceled
if (cancelExistingReminders(calItem) && !calItemCanceled)
scheduleNextReminders(calItem, true, true);
}
}
}
if (notification.mods.deleted != null) {
for (Map.Entry<ModificationKey, Change> entry : notification.mods.deleted.entrySet()) {
MailItem.Type type = (MailItem.Type) entry.getValue().what;
if (type == MailItem.Type.APPOINTMENT || type == MailItem.Type.TASK) {
Mailbox mbox = null;
try {
mbox = MailboxManager.getInstance().getMailboxByAccount(account, MailboxManager.FetchMode.DO_NOT_AUTOCREATE);
} catch (ServiceException e) {
ZimbraLog.scheduler.error("Error looking up the mailbox of account %s", account.getId(), e);
}
if (mbox != null) {
cancelExistingReminders(entry.getKey().getItemId(), mbox.getId());
}
}
}
}
}
use of com.zimbra.cs.mailbox.MailItem in project zm-mailbox by Zimbra.
the class ItemActionHelper method executeRemote.
private void executeRemote() throws ServiceException, IOException {
Account target = Provisioning.getInstance().get(Key.AccountBy.id, mIidFolder.getAccountId());
AuthToken at = getAuthToken();
String pxyAuthToken = Provisioning.onLocalServer(target) ? null : at.getProxyAuthToken();
ZAuthToken zat = null;
if (pxyAuthToken == null) {
zat = at.toZAuthToken();
zat.resetProxyAuthToken();
} else {
zat = new ZAuthToken(pxyAuthToken);
}
ZMailbox.Options zoptions = new ZMailbox.Options(zat, AccountUtil.getSoapUri(target));
zoptions.setNoSession(true);
zoptions.setTargetAccount(target.getId());
zoptions.setTargetAccountBy(Key.AccountBy.id);
ZMailbox zmbx = ZMailbox.getMailbox(zoptions);
// check for mountpoints before going any further...
ZFolder zfolder = zmbx.getFolderById(mIidFolder.toString(mAuthenticatedAccount));
if (zfolder instanceof ZMountpoint) {
ItemId iidTarget = new ItemId(((ZMountpoint) zfolder).getCanonicalRemoteId(), mAuthenticatedAccount.getId());
if (!mIidFolder.equals(iidTarget)) {
mIidFolder = iidTarget;
if (++mHopCount > com.zimbra.soap.ZimbraSoapContext.MAX_HOP_COUNT)
throw MailServiceException.TOO_MANY_HOPS(mIidRequestedFolder);
schedule();
return;
}
}
boolean deleteOriginal = mOperation != Op.COPY;
String folderStr = mIidFolder.toString();
mCreatedIds = new ArrayList<String>(itemIds.length);
boolean toSpam = mIidFolder.getId() == Mailbox.ID_FOLDER_SPAM;
boolean toMailbox = !toSpam && mIidFolder.getId() != Mailbox.ID_FOLDER_TRASH;
for (MailItem item : mMailbox.getItemById(mOpCtxt, itemIds, type)) {
if (item == null) {
continue;
}
List<Message> msgs = null;
if (item instanceof Conversation) {
msgs = mMailbox.getMessagesByConversation(mOpCtxt, item.getId(), SortBy.DATE_ASC, -1);
}
if (deleteOriginal) {
if (msgs != null) {
// determine which of the conversation's component messages are actually able to be moved
boolean permDenied = false;
for (Iterator<Message> it = msgs.iterator(); it.hasNext(); ) {
Message msg = it.next();
if (!TargetConstraint.checkItem(mTargetConstraint, msg)) {
it.remove();
} else if (!canDelete(msg)) {
it.remove();
permDenied = true;
}
}
// stop here if no messages would be moved...
if (msgs.isEmpty()) {
if (permDenied) {
throw ServiceException.PERM_DENIED("cannot delete any messages in " + item.getType() + " " + item.getId());
}
// all messages were excluded by the TargetConstraint, so there's no failure...
continue;
}
} else {
if (!canDelete(item)) {
throw ServiceException.PERM_DENIED("cannot delete existing copy of " + item.getType() + " " + item.getId());
}
}
}
boolean fromSpam = item.inSpam();
if ((fromSpam && toMailbox) || (!fromSpam && toSpam)) {
try {
Folder dest = mMailbox.getFolderById(mOpCtxt, mIidFolder.getId());
SpamReport report = new SpamReport(toSpam, "remote " + mOperation, dest.getPath());
Folder source = mMailbox.getFolderById(mOpCtxt, item.getFolderId());
report.setSourceFolderPath(source.getPath());
report.setDestAccountName(target.getName());
SpamHandler.getInstance().handle(mOpCtxt, mMailbox, item.getId(), item.getType(), report);
} catch (OutOfMemoryError e) {
Zimbra.halt("out of memory", e);
} catch (Throwable t) {
ZimbraLog.mailop.info("could not train spam filter: " + new ItemId(item).toString(), t);
}
}
// since we can't apply tags to a remote object, hardwiring "tags" to null below...
String flags = (mOperation == Op.UPDATE && mFlags != null ? mFlags : item.getFlagString());
String name = ((mOperation == Op.RENAME || mOperation == Op.UPDATE) && mName != null ? mName : item.getName());
String createdId = null;
InputStream in = null;
switch(item.getType()) {
case CONTACT:
Contact ct = (Contact) item;
Map<String, ZMailbox.ZAttachmentInfo> attachments = new HashMap<String, ZMailbox.ZAttachmentInfo>();
for (Contact.Attachment att : ct.getAttachments()) {
String attachmentId = zmbx.uploadAttachment(att.getFilename(), att.getContent(), att.getContentType(), 0);
ZMailbox.ZAttachmentInfo info = new ZMailbox.ZAttachmentInfo().setAttachmentId(attachmentId);
attachments.put(att.getName(), info);
}
Map<String, String> fields = ct.getFields();
Map<String, String> members = new HashMap<String, String>();
for (String key : fields.keySet()) {
if (ContactConstants.A_groupMember.equals(key)) {
String memberEncoded = fields.get(key);
ContactGroup group = ContactGroup.init(memberEncoded);
for (Member m : group.getMembers()) {
members.put(m.getValue(), m.getType().getSoapEncoded());
}
break;
}
}
fields.remove(ContactConstants.A_groupMember);
ZContact contact = zmbx.createContact(folderStr, null, fields, attachments, members);
createdId = contact.getId();
mCreatedIds.add(createdId);
break;
case MESSAGE:
try {
in = StoreManager.getInstance().getContent(item.getBlob());
createdId = zmbx.addMessage(folderStr, flags, null, item.getDate(), in, item.getSize(), true);
} finally {
ByteUtil.closeStream(in);
}
mCreatedIds.add(createdId);
break;
case VIRTUAL_CONVERSATION:
case CONVERSATION:
for (Message msg : msgs) {
flags = (mOperation == Op.UPDATE && mFlags != null ? mFlags : msg.getFlagString());
try {
in = StoreManager.getInstance().getContent(msg.getBlob());
createdId = zmbx.addMessage(folderStr, flags, null, msg.getDate(), in, msg.getSize(), true);
} finally {
ByteUtil.closeStream(in);
}
mCreatedIds.add(createdId);
}
break;
case DOCUMENT:
Document doc = (Document) item;
SoapHttpTransport transport = new SoapHttpTransport(zoptions.getUri());
try {
in = StoreManager.getInstance().getContent(doc.getBlob());
String uploadId = zmbx.uploadContentAsStream(name, in, doc.getContentType(), doc.getSize(), 4000, true);
// instead of using convenience method from ZMailbox
// we need to hand marshall the request and set the
// response protocol explicitly to what was requested
// from the client.
Element req = new XMLElement(MailConstants.SAVE_DOCUMENT_REQUEST);
Element edoc = req.addUniqueElement(MailConstants.E_DOC);
edoc.addAttribute(MailConstants.A_NAME, name);
edoc.addAttribute(MailConstants.A_FOLDER, folderStr);
edoc.addAttribute(MailConstants.A_FLAGS, flags);
Element upload = edoc.addElement(MailConstants.E_UPLOAD);
upload.addAttribute(MailConstants.A_ID, uploadId);
transport.setResponseProtocol(mResponseProtocol);
transport.setAuthToken(zat);
Element response = transport.invoke(req);
createdId = response.getElement(MailConstants.E_DOC).getAttribute(MailConstants.A_ID);
} finally {
ByteUtil.closeStream(in);
transport.shutdown();
}
mCreatedIds.add(createdId);
break;
case APPOINTMENT:
case TASK:
CalendarItem cal = (CalendarItem) item;
// private calendar item may not be moved by non-owner unless permission was granted
if (!cal.isPublic()) {
boolean asAdmin = mOpCtxt != null ? mOpCtxt.isUsingAdminPrivileges() : false;
if (!cal.allowPrivateAccess(mAuthenticatedAccount, asAdmin))
throw ServiceException.PERM_DENIED("you do not have permission to move/copy a private calendar item from the current folder/mailbox");
}
// Move the item to remote mailbox using SetAppointmentRequest/SetTaskRequest.
QName qname = (item.getType() == MailItem.Type.TASK ? MailConstants.SET_TASK_REQUEST : MailConstants.SET_APPOINTMENT_REQUEST);
Element request = new Element.XMLElement(qname).addAttribute(MailConstants.A_FOLDER, folderStr).addAttribute(MailConstants.A_FLAGS, flags);
ToXML.encodeAlarmTimes(request, cal);
Invite invDefault = cal.getDefaultInviteOrNull();
// Takeover as organizer if we're doing a MOVE and source mailbox is the organizer.
// Don't takeover in a COPY operation.
boolean takeoverAsOrganizer = false;
boolean blockMove = false;
if (Op.MOVE.equals(mOperation)) {
Invite inv = invDefault;
if (inv == null) {
// no default invite; let's use the first invite
Invite[] invs = cal.getInvites();
if (invs != null && invs.length > 0)
inv = invs[0];
}
takeoverAsOrganizer = inv != null && inv.isOrganizer();
blockMove = takeoverAsOrganizer && inv.hasOtherAttendees();
}
if (blockMove) {
throw MailServiceException.INVALID_REQUEST("This operation requires change of organizer and it is not permitted", null);
}
if (invDefault != null) {
addCalendarPart(request.addUniqueElement(MailConstants.A_DEFAULT), cal, invDefault, zmbx, target, takeoverAsOrganizer);
}
for (Invite inv : cal.getInvites()) {
if (inv == null || inv == invDefault)
continue;
String elem = inv.isCancel() ? MailConstants.E_CAL_CANCEL : MailConstants.E_CAL_EXCEPT;
addCalendarPart(request.addElement(elem), cal, inv, zmbx, target, takeoverAsOrganizer);
}
ToXML.encodeCalendarReplies(request, cal);
createdId = zmbx.invoke(request).getAttribute(MailConstants.A_CAL_ID);
mCreatedIds.add(createdId);
break;
default:
throw MailServiceException.CANNOT_COPY(item.getId());
}
try {
if (deleteOriginal && !mIdFormatter.formatItemId(item).equals(createdId)) {
if (msgs == null) {
mMailbox.delete(mOpCtxt, item.getId(), item.getType());
} else {
for (Message msg : msgs) mMailbox.delete(mOpCtxt, msg.getId(), msg.getType());
}
}
} catch (ServiceException e) {
if (e.getCode() != ServiceException.PERM_DENIED)
throw e;
// something funky happened permissions-wise between the getEffectivePermissions check and here...
ZimbraLog.misc.info("could not delete original item " + item.getId() + "; treating operation as a copy instead");
}
}
}
use of com.zimbra.cs.mailbox.MailItem in project zm-mailbox by Zimbra.
the class ItemActionHelper method executeLocalBatch.
private void executeLocalBatch(int[] ids) throws ServiceException {
// iterate over the local items and perform the requested operation
switch(mOperation) {
case FLAG:
getMailbox().alterTag(getOpCtxt(), ids, type, Flag.FlagInfo.FLAGGED, mFlagValue, mTargetConstraint);
break;
case PRIORITY:
getMailbox().alterTag(getOpCtxt(), ids, type, Flag.FlagInfo.PRIORITY, mFlagValue, mTargetConstraint);
break;
case READ:
getMailbox().alterTag(getOpCtxt(), ids, type, Flag.FlagInfo.UNREAD, !mFlagValue, mTargetConstraint);
break;
case TAG:
getMailbox().alterTag(getOpCtxt(), ids, type, mTagName, mFlagValue, mTargetConstraint);
break;
case COLOR:
getMailbox().setColor(getOpCtxt(), ids, type, mColor);
break;
case HARD_DELETE:
getMailbox().delete(getOpCtxt(), ids, type, mTargetConstraint);
break;
case RECOVER:
getMailbox().recover(getOpCtxt(), ids, type, mIidFolder.getId());
break;
case DUMPSTER_DELETE:
getMailbox().deleteFromDumpster(getOpCtxt(), ids);
break;
case SPAM:
case MOVE:
getMailbox().move(getOpCtxt(), ids, type, mIidFolder.getId(), mTargetConstraint);
break;
case COPY:
List<MailItem> copies = getMailbox().copy(getOpCtxt(), ids, type, mIidFolder.getId());
mCreatedIds = new ArrayList<String>(ids.length);
for (MailItem item : copies) {
mCreatedIds.add(mIdFormatter.formatItemId(item));
}
break;
case RENAME:
for (int id : ids) {
getMailbox().rename(getOpCtxt(), id, type, mName, mIidFolder.getId());
}
break;
case UPDATE:
if (mName != null) {
for (int id : ids) {
getMailbox().rename(getOpCtxt(), id, type, mName, mIidFolder.getId());
}
} else if (mIidFolder.getId() > 0) {
getMailbox().move(getOpCtxt(), ids, type, mIidFolder.getId(), mTargetConstraint);
}
if (mTags != null || mFlags != null) {
int flagMask = Flag.toBitmask(mFlags);
if (mFlags == null) {
flagMask = MailItem.FLAG_UNCHANGED;
}
if (mTags == null) {
mTags = MailItem.TAG_UNCHANGED;
}
getMailbox().setTags(getOpCtxt(), ids, type, flagMask, mTags, mTargetConstraint);
}
if (mColor != null) {
getMailbox().setColor(getOpCtxt(), ids, type, mColor);
}
break;
case LOCK:
for (int id : ids) {
getMailbox().lock(getOpCtxt(), id, type, mAuthenticatedAccount.getId());
}
break;
case UNLOCK:
for (int id : ids) {
getMailbox().unlock(getOpCtxt(), id, type, mAuthenticatedAccount.getId());
}
break;
default:
throw ServiceException.INVALID_REQUEST("unknown operation: " + mOperation, null);
}
}
Aggregations