public void findResources(ServerInfo serverInfo)
      throws URISyntaxException, DavException, HttpException, IOException {
    // CardDAV
    Log.i(TAG, "*** Starting CardDAV resource detection");
    WebDavResource principal = getCurrentUserPrincipal(serverInfo, "carddav");
    URI uriAddressBookHomeSet = null;
    try {
      principal.propfind(Mode.HOME_SETS);
      uriAddressBookHomeSet = principal.getProperties().getAddressbookHomeSet();
    } catch (Exception e) {
      Log.i(TAG, "Couldn't find address-book home set", e);
    }
    if (uriAddressBookHomeSet != null) {
      Log.i(TAG, "Found address-book home set: " + uriAddressBookHomeSet);

      WebDavResource homeSetAddressBooks = new WebDavResource(principal, uriAddressBookHomeSet);
      if (checkHomesetCapabilities(homeSetAddressBooks, "addressbook")) {
        serverInfo.setCardDAV(true);
        homeSetAddressBooks.propfind(Mode.CARDDAV_COLLECTIONS);

        List<WebDavResource> possibleAddressBooks = new LinkedList<>();
        possibleAddressBooks.add(homeSetAddressBooks);
        if (homeSetAddressBooks.getMembers() != null)
          possibleAddressBooks.addAll(homeSetAddressBooks.getMembers());

        List<ServerInfo.ResourceInfo> addressBooks = new LinkedList<>();
        for (WebDavResource resource : possibleAddressBooks) {
          final WebDavResource.Properties properties = resource.getProperties();
          if (properties.isAddressBook()) {
            Log.i(TAG, "Found address book: " + resource.getLocation().getPath());
            ServerInfo.ResourceInfo info =
                new ServerInfo.ResourceInfo(
                    ServerInfo.ResourceInfo.Type.ADDRESS_BOOK,
                    properties.isReadOnly(),
                    resource.getLocation().toString(),
                    properties.getDisplayName(),
                    properties.getDescription(),
                    properties.getColor());

            addressBooks.add(info);
          }
        }
        serverInfo.setAddressBooks(addressBooks);
      } else Log.w(TAG, "Found address-book home set, but it doesn't advertise CardDAV support");
    }

    // CalDAV
    Log.i(TAG, "*** Starting CalDAV resource detection");
    principal = getCurrentUserPrincipal(serverInfo, "caldav");
    URI uriCalendarHomeSet = null;
    try {
      principal.propfind(Mode.HOME_SETS);
      uriCalendarHomeSet = principal.getProperties().getCalendarHomeSet();
    } catch (Exception e) {
      Log.i(TAG, "Couldn't find calendar home set", e);
    }
    if (uriCalendarHomeSet != null) {
      Log.i(TAG, "Found calendar home set: " + uriCalendarHomeSet);

      WebDavResource homeSetCalendars = new WebDavResource(principal, uriCalendarHomeSet);
      if (checkHomesetCapabilities(homeSetCalendars, "calendar-access")) {
        serverInfo.setCalDAV(true);
        homeSetCalendars.propfind(Mode.CALDAV_COLLECTIONS);

        List<WebDavResource> possibleCalendars = new LinkedList<>();
        possibleCalendars.add(homeSetCalendars);
        if (homeSetCalendars.getMembers() != null)
          possibleCalendars.addAll(homeSetCalendars.getMembers());

        List<ServerInfo.ResourceInfo> calendars = new LinkedList<>(),
            todoLists = new LinkedList<>();
        for (WebDavResource resource : possibleCalendars) {
          final WebDavResource.Properties properties = resource.getProperties();
          if (properties.isCalendar()) {
            Log.i(TAG, "Found calendar: " + resource.getLocation().getPath());
            ServerInfo.ResourceInfo info =
                new ServerInfo.ResourceInfo(
                    ServerInfo.ResourceInfo.Type.CALENDAR,
                    properties.isReadOnly(),
                    resource.getLocation().toString(),
                    properties.getDisplayName(),
                    properties.getDescription(),
                    properties.getColor());
            info.setTimezone(properties.getTimeZone());

            boolean isCalendar = false, isTodoList = false;
            if (properties.getSupportedComponents() == null) {
              // no info about supported components, assuming all components are supported
              isCalendar = true;
              isTodoList = true;
            } else {
              // CALDAV:supported-calendar-component-set available
              for (String supportedComponent : properties.getSupportedComponents())
                if ("VEVENT".equalsIgnoreCase(supportedComponent)) isCalendar = true;
                else if ("VTODO".equalsIgnoreCase(supportedComponent)) isTodoList = true;

              if (!isCalendar && !isTodoList) {
                Log.i(TAG, "Ignoring this calendar because it supports neither VEVENT nor VTODO");
                continue;
              }
            }

            // use a copy constructor to allow different "enabled" status for calendars and todo
            // lists
            if (isCalendar) calendars.add(new ServerInfo.ResourceInfo(info));
            if (isTodoList) todoLists.add(new ServerInfo.ResourceInfo(info));
          }
        }

        serverInfo.setCalendars(calendars);
        serverInfo.setTodoLists(todoLists);
      } else Log.w(TAG, "Found calendar home set, but it doesn't advertise CalDAV support");
    }

    if (!serverInfo.isCalDAV() && !serverInfo.isCardDAV())
      throw new DavIncapableException(context.getString(R.string.setup_neither_caldav_nor_carddav));
  }