Exemple #1
0
  @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 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);
    }
  }
 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;
       }
     }
   }
 }
  @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);
      }
    }
  }