@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 meta = request.getElement(MailConstants.E_METADATA); String section = meta.getAttribute(MailConstants.A_SECTION); section = section.trim(); if (section.length() == 0 || section.length() > 36) throw ServiceException.INVALID_REQUEST( "invalid length for custom metadata section name", null); CustomMetadata custom = new CustomMetadata(section); for (Element.KeyValuePair kvp : meta.listKeyValuePairs()) custom.put(kvp.getKey(), kvp.getValue()); ItemId iid = new ItemId(request.getAttribute(MailConstants.A_ID), zsc); mbox.setCustomData(octxt, iid.getId(), MailItem.Type.UNKNOWN, custom); Element response = zsc.createElement(MailConstants.SET_METADATA_RESPONSE); response.addAttribute(MailConstants.A_ID, ifmt.formatItemId(iid)); return response; }
private static void searchLocalAccountCalendars( Element parent, SearchParams params, OperationContext octxt, ZimbraSoapContext zsc, Account authAcct, Mailbox targetMbox, List<Integer> folderIds, MailItem.Type type) throws ServiceException { ItemIdFormatter ifmt = new ItemIdFormatter(authAcct.getId(), targetMbox.getAccountId(), false); long rangeStart = params.getCalItemExpandStart(); long rangeEnd = params.getCalItemExpandEnd(); for (int folderId : folderIds) { try { CalendarDataResult result = targetMbox.getCalendarSummaryForRange(octxt, folderId, type, rangeStart, rangeEnd); if (result != null) { addCalendarDataToResponse(parent, zsc, ifmt, result.data, result.allowPrivateAccess); } } catch (ServiceException e) { String ecode = e.getCode(); if (ecode.equals(ServiceException.PERM_DENIED)) { // share permission was revoked ZimbraLog.calendar.warn( "Ignoring permission error during calendar search of folder " + ifmt.formatItemId(folderId), e); } else if (ecode.equals(MailServiceException.NO_SUCH_FOLDER)) { // shared calendar folder was deleted by the owner ZimbraLog.calendar.warn( "Ignoring deleted calendar folder " + ifmt.formatItemId(folderId)); } else { throw e; } } } }
private static void searchRemoteAccountCalendars( Element parent, SearchParams params, ZimbraSoapContext zsc, Account authAcct, Map<String, List<Integer>> accountFolders) throws ServiceException { String nominalTargetAcctId = null; // mail service soap requests want to see a target account StringBuilder queryStr = new StringBuilder(); for (Map.Entry<String, List<Integer>> entry : accountFolders.entrySet()) { String acctId = entry.getKey(); if (nominalTargetAcctId == null) nominalTargetAcctId = acctId; ItemIdFormatter ifmt = new ItemIdFormatter(authAcct.getId(), acctId, false); List<Integer> folderIds = entry.getValue(); for (int folderId : folderIds) { if (queryStr.length() > 0) queryStr.append(" OR "); // must quote the qualified folder id queryStr.append("inid:\"").append(ifmt.formatItemId(folderId)).append("\""); } } Element req = zsc.createElement(MailConstants.SEARCH_REQUEST); req.addAttribute(MailConstants.A_SEARCH_TYPES, MailItem.Type.toString(params.getTypes())); if (params.getSortBy() != null) { req.addAttribute(MailConstants.A_SORTBY, params.getSortBy().toString()); } req.addAttribute(MailConstants.A_QUERY_OFFSET, params.getOffset()); if (params.getLimit() != 0) req.addAttribute(MailConstants.A_QUERY_LIMIT, params.getLimit()); req.addAttribute(MailConstants.A_CAL_EXPAND_INST_START, params.getCalItemExpandStart()); req.addAttribute(MailConstants.A_CAL_EXPAND_INST_END, params.getCalItemExpandEnd()); req.addAttribute(MailConstants.E_QUERY, queryStr.toString(), Element.Disposition.CONTENT); Account target = Provisioning.getInstance().get(Key.AccountBy.id, nominalTargetAcctId); String pxyAuthToken = zsc.getAuthToken().getProxyAuthToken(); ZAuthToken zat = pxyAuthToken == null ? zsc.getRawAuthToken() : new ZAuthToken(pxyAuthToken); ZMailbox.Options zoptions = new ZMailbox.Options(zat, AccountUtil.getSoapUri(target)); zoptions.setTargetAccount(nominalTargetAcctId); zoptions.setTargetAccountBy(AccountBy.id); zoptions.setNoSession(true); ZMailbox zmbx = ZMailbox.getMailbox(zoptions); Element resp = zmbx.invoke(req); for (Element hit : resp.listElements()) { hit.detach(); parent.addElement(hit); } }
@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); int flags = Flag.toBitmask(request.getAttribute(MailConstants.A_FLAGS, null)); String[] tags = TagUtil.parseTags(request, mbox, octxt); mbox.lock.lock(); try { int defaultFolder = getItemType() == MailItem.Type.TASK ? Mailbox.ID_FOLDER_TASKS : Mailbox.ID_FOLDER_CALENDAR; String defaultFolderStr = Integer.toString(defaultFolder); String folderIdStr = request.getAttribute(MailConstants.A_FOLDER, defaultFolderStr); ItemId iidFolder = new ItemId(folderIdStr, zsc); Folder folder = mbox.getFolderById(octxt, iidFolder.getId()); SetCalendarItemParseResult parsed = parseSetAppointmentRequest(request, zsc, octxt, folder, getItemType(), false); CalendarItem calItem = mbox.setCalendarItem( octxt, iidFolder.getId(), flags, tags, parsed.defaultInv, parsed.exceptions, parsed.replies, parsed.nextAlarm); Element response = getResponseElement(zsc); if (parsed.defaultInv != null) { response .addElement(MailConstants.A_DEFAULT) .addAttribute( MailConstants.A_ID, ifmt.formatItemId(parsed.defaultInv.invite.getMailItemId())); } if (parsed.exceptions != null) { for (SetCalendarItemData cur : parsed.exceptions) { Element e = response.addElement(MailConstants.E_CAL_EXCEPT); e.addAttribute(MailConstants.A_CAL_RECURRENCE_ID, cur.invite.getRecurId().toString()); e.addAttribute(MailConstants.A_ID, ifmt.formatItemId(cur.invite.getMailItemId())); } } String itemId = ifmt.formatItemId(calItem == null ? 0 : calItem.getId()); response.addAttribute(MailConstants.A_CAL_ID, itemId); try { Element inv = request .getElement(MailConstants.A_DEFAULT) .getElement(MailConstants.E_MSG) .getElement(MailConstants.E_INVITE); Element comp = inv.getOptionalElement(MailConstants.E_INVITE_COMPONENT); if (comp != null) { inv = comp; } String reqCalItemId = inv.getAttribute(MailConstants.A_CAL_ID); String uid = inv.getAttribute(MailConstants.A_UID); boolean uidSame = (calItem == null || (calItem.getUid() == null && uid == null) || (calItem.getUid() != null && (calItem.getUid().equals(uid) || (Invite.isOutlookUid(calItem.getUid()) && calItem .getUid() .equalsIgnoreCase( uid))))); // new or same as requested, or Outlook and // case-insensitive equal if (ZimbraLog.calendar.isInfoEnabled()) { StringBuilder logBuf = new StringBuilder(); if (!reqCalItemId.equals(itemId)) { logBuf .append("Mapped requested id ") .append(reqCalItemId) .append(" -> ") .append(itemId); } if (!uidSame) { logBuf .append(" ?? requested UID ") .append(uid) .append(" differs from mapped ") .append(calItem.getUid()); ZimbraLog.calendar.warn(logBuf.toString()); } else if (logBuf.length() > 0) { ZimbraLog.calendar.info(logBuf.toString()); } } assert (uidSame); } catch (ServiceException se) { // one of the elements we wanted to use doesn't exist; ignore; no log/assertion possible } if (!parsed.isTodo) response.addAttribute(MailConstants.A_APPT_ID_DEPRECATE_ME, itemId); // for backward compat return response; } finally { mbox.lock.release(); } }
private static void runSimpleAppointmentQuery( Element parent, SearchParams params, OperationContext octxt, ZimbraSoapContext zsc, Account authAcct, Mailbox mbox, List<String> folderIdStrs) throws ServiceException { Set<MailItem.Type> types = params.getTypes(); MailItem.Type type = types.size() == 1 ? Iterables.getOnlyElement(types) : MailItem.Type.APPOINTMENT; if (params.getSortBy() != null) { parent.addAttribute(MailConstants.A_SORTBY, params.getSortBy().toString()); } parent.addAttribute(MailConstants.A_QUERY_OFFSET, params.getOffset()); parent.addAttribute(MailConstants.A_QUERY_MORE, false); List<ItemId> folderIids = new ArrayList<ItemId>(folderIdStrs.size()); for (String folderIdStr : folderIdStrs) { folderIids.add(new ItemId(folderIdStr, zsc)); } Provisioning prov = Provisioning.getInstance(); MailboxManager mboxMgr = MailboxManager.getInstance(); Server localServer = prov.getLocalServer(); Map<Server, Map<String /* account id */, List<Integer> /* folder ids */>> groupedByServer = groupByServer(ItemId.groupFoldersByAccount(octxt, mbox, folderIids)); // Look up in calendar cache first. if (LC.calendar_cache_enabled.booleanValue()) { CalSummaryCache calCache = CalendarCacheManager.getInstance().getSummaryCache(); long rangeStart = params.getCalItemExpandStart(); long rangeEnd = params.getCalItemExpandEnd(); for (Iterator<Map.Entry<Server, Map<String, List<Integer>>>> serverIter = groupedByServer.entrySet().iterator(); serverIter.hasNext(); ) { Map.Entry<Server, Map<String, List<Integer>>> serverMapEntry = serverIter.next(); Map<String, List<Integer>> accountFolders = serverMapEntry.getValue(); // for each account for (Iterator<Map.Entry<String, List<Integer>>> acctIter = accountFolders.entrySet().iterator(); acctIter.hasNext(); ) { Map.Entry<String, List<Integer>> acctEntry = acctIter.next(); String acctId = acctEntry.getKey(); List<Integer> folderIds = acctEntry.getValue(); ItemIdFormatter ifmt = new ItemIdFormatter(authAcct.getId(), acctId, false); // for each folder for (Iterator<Integer> iterFolderId = folderIds.iterator(); iterFolderId.hasNext(); ) { int folderId = iterFolderId.next(); try { CalendarDataResult result = calCache.getCalendarSummary( octxt, acctId, folderId, type, rangeStart, rangeEnd, true); if (result != null) { // Found data in cache. iterFolderId.remove(); addCalendarDataToResponse( parent, zsc, ifmt, result.data, result.allowPrivateAccess); } } catch (ServiceException e) { String ecode = e.getCode(); if (ecode.equals(ServiceException.PERM_DENIED)) { // share permission was revoked ZimbraLog.calendar.warn( "Ignoring permission error during calendar search of folder " + ifmt.formatItemId(folderId), e); } else if (ecode.equals(MailServiceException.NO_SUCH_FOLDER)) { // shared calendar folder was deleted by the owner ZimbraLog.calendar.warn( "Ignoring deleted calendar folder " + ifmt.formatItemId(folderId)); } else { throw e; } iterFolderId.remove(); } } if (folderIds.isEmpty()) acctIter.remove(); } if (accountFolders.isEmpty()) serverIter.remove(); } } // For any remaining calendars, we have to get the data the hard way. for (Map.Entry<Server, Map<String, List<Integer>>> serverMapEntry : groupedByServer.entrySet()) { Server server = serverMapEntry.getKey(); Map<String, List<Integer>> accountFolders = serverMapEntry.getValue(); if (server.equals(localServer)) { // local server for (Map.Entry<String, List<Integer>> entry : accountFolders.entrySet()) { String acctId = entry.getKey(); List<Integer> folderIds = entry.getValue(); if (folderIds.isEmpty()) continue; Account targetAcct = prov.get(AccountBy.id, acctId); if (targetAcct == null) { ZimbraLog.calendar.warn( "Skipping unknown account " + acctId + " during calendar search"); continue; } Mailbox targetMbox = mboxMgr.getMailboxByAccount(targetAcct); searchLocalAccountCalendars( parent, params, octxt, zsc, authAcct, targetMbox, folderIds, type); } } else { // remote server searchRemoteAccountCalendars(parent, params, zsc, authAcct, accountFolders); } } }