Example #1
0
 public void createSearchParams(String searchQuery) {
   mSearchParams = new SearchParams();
   mSearchParams.setLimit(mLimit + 1);
   mSearchParams.setSortBy(SortBy.NAME_ASC);
   mSearchParams.setQueryString(searchQuery);
   mSearchParams.setTypes(EnumSet.of(MailItem.Type.CONTACT));
 }
Example #2
0
 public void parseSearchParams(Element request, String searchQuery) throws ServiceException {
   if (request == null || mSoapContext == null) {
     createSearchParams(searchQuery);
     return;
   }
   setRequest(request);
   // bug 69338
   // SearchParams.parse relies on A_SEARCH_TYPES on the request to determine search type,
   // which will then determine if cursor should be used to narrow db query.
   // If A_SEARCH_TYPES is not set, default type is conversation, cursor is not used to
   // narrow db query for conversations.   We do not require clients to set types
   // on GAL soap APIs.  Set it to "contact" here.
   request.addAttribute(MailConstants.A_SEARCH_TYPES, MailItem.Type.CONTACT.toString());
   mSearchParams = SearchParams.parse(request, mSoapContext, searchQuery);
   mSearchParams.setTypes(EnumSet.of(MailItem.Type.CONTACT));
   setLimit(mSearchParams.getLimit());
 }
Example #3
0
 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;
       }
     }
   }
 }
Example #4
0
  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);
    }
  }
Example #5
0
 /**
  * Returns list of folder id string if the query is a simple appointments query. Otherwise returns
  * null.
  *
  * @param params search parameters
  * @param zsc not used, may be used in subclass
  * @throws ServiceException subclass may throw
  */
 protected List<String> getFolderIdListIfSimpleAppointmentsQuery(
     SearchParams params, ZimbraSoapContext zsc) throws ServiceException {
   // types = "appointment"
   Set<MailItem.Type> types = params.getTypes();
   if (types.size() != 1) {
     return null;
   }
   MailItem.Type type = Iterables.getOnlyElement(types);
   if (type != MailItem.Type.APPOINTMENT && type != MailItem.Type.TASK) {
     return null;
   }
   // has time range
   if (params.getCalItemExpandStart() == -1 || params.getCalItemExpandEnd() == -1) {
     return null;
   }
   // offset = 0
   if (params.getOffset() != 0) {
     return null;
   }
   // sortBy = "none"
   SortBy sortBy = params.getSortBy();
   if (sortBy != null && !sortBy.equals(SortBy.NONE)) {
     return null;
   }
   // query string is "inid:<folder> [OR inid:<folder>]*"
   String queryString = Strings.nullToEmpty(params.getQueryString());
   queryString = queryString.toLowerCase();
   queryString = removeOuterParens(queryString);
   // simple appointment query can't have any ANDed terms
   if (queryString.contains("and")) {
     return null;
   }
   String[] terms = queryString.split("\\s+or\\s+");
   List<String> folderIdStrs = new ArrayList<String>();
   for (String term : terms) {
     term = term.trim();
     // remove outermost parentheses (light client does this, e.g. "(inid:10)")
     term = removeOuterParens(term);
     if (!term.startsWith("inid:")) {
       return null;
     }
     String folderId = term.substring(5); // everything after "inid:"
     folderId =
         unquote(folderId); // e.g. if query is: inid:"account-id:num", we want just account-id:num
     if (folderId.length() > 0) {
       folderIdStrs.add(folderId);
     }
   }
   return folderIdStrs;
 }
Example #6
0
  @Override
  public Element handle(Element request, Map<String, Object> context) throws ServiceException {
    ZimbraSoapContext zsc = getZimbraSoapContext(context);
    Mailbox mbox = getRequestedMailbox(zsc);
    Account account = getRequestedAccount(zsc);
    OperationContext octxt = getOperationContext(zsc, context);

    SearchRequest req = JaxbUtil.elementToJaxb(request);
    if (Objects.firstNonNull(req.getWarmup(), false)) {
      mbox.index.getIndexStore().warmup();
      return zsc.createElement(MailConstants.SEARCH_RESPONSE);
    }

    SearchParams params = SearchParams.parse(req, zsc, account.getPrefMailInitialSearch());
    if (params.getLocale() == null) {
      params.setLocale(mbox.getAccount().getLocale());
    }
    if (params.inDumpster() && params.getTypes().contains(MailItem.Type.CONVERSATION)) {
      throw ServiceException.INVALID_REQUEST("cannot search for conversations in dumpster", null);
    }

    if (LC.calendar_cache_enabled.booleanValue()) {
      List<String> apptFolderIds = getFolderIdListIfSimpleAppointmentsQuery(params, zsc);
      if (apptFolderIds != null) {
        Account authAcct = getAuthenticatedAccount(zsc);
        Element response = zsc.createElement(MailConstants.SEARCH_RESPONSE);
        runSimpleAppointmentQuery(response, params, octxt, zsc, authAcct, mbox, apptFolderIds);
        return response;
      }
    }

    ZimbraQueryResults results = mbox.index.search(zsc.getResponseProtocol(), octxt, params);
    try {
      // create the XML response Element
      Element response = zsc.createElement(MailConstants.SEARCH_RESPONSE);
      // must use results.getSortBy() because the results might have ignored our sortBy
      // request and used something else...
      response.addAttribute(MailConstants.A_SORTBY, results.getSortBy().toString());
      putHits(zsc, octxt, response, results, params);
      return response;
    } finally {
      Closeables.closeQuietly(results);
    }
  }
Example #7
0
  private void putHits(
      ZimbraSoapContext zsc,
      OperationContext octxt,
      Element el,
      ZimbraQueryResults results,
      SearchParams params)
      throws ServiceException {

    if (params.getInlineRule() == ExpandResults.HITS) {
      // "hits" is not a valid value for Search...
      params.setInlineRule(ExpandResults.NONE);
    }

    ResultsPager pager = ResultsPager.create(results, params);
    if (params.getCursor() != null) {
      if (params.getCursor().isIncludeOffset()) {
        long offset = pager.getCursorOffset();
        if (offset >= 0) {
          el.addAttribute(MailConstants.A_QUERY_OFFSET, offset);
        }
      }
    } else {
      el.addAttribute(MailConstants.A_QUERY_OFFSET, params.getOffset());
    }

    SearchResponse resp = new SearchResponse(zsc, octxt, el, params);
    resp.setIncludeMailbox(false);
    resp.setSortOrder(pager.getSortOrder());

    while (pager.hasNext() && resp.size() < params.getLimit()) {
      ZimbraHit hit = pager.getNextHit();
      resp.add(hit);
    }

    resp.addHasMore(pager.hasNext());
    resp.add(results.getResultInfo());
  }
Example #8
0
  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);
      }
    }
  }