Click or drag to resize

IAddressbookFolder Interface

IT Hit WebDAV Classes Reference
Represents address book on a CardDAV server.

Namespace:  ITHit.WebDAV.Server.CardDav
Assembly:  ITHit.WebDAV.Server (in ITHit.WebDAV.Server.dll) Version: 13.3.13068
Syntax
public interface IAddressbookFolder : IAddressbookItem, 
	IFolder, IItemCollection, IHierarchyItem, IHierarchyItemBase, IAddressbookReport

The IAddressbookFolder type exposes the following members.

Properties
  NameDescription
Public propertyAddressbookDescription
Gets a human-readable description of the address book.
Public propertyCode exampleCreated
Gets the creation date of the item in repository expressed as the coordinated universal time (UTC).
(Inherited from IHierarchyItemBase.)
Public propertyCode exampleModified
Gets the last modification date of the item in repository expressed as the coordinated universal time (UTC).
(Inherited from IHierarchyItemBase.)
Public propertyCode exampleName
Gets the name of the item in repository.
(Inherited from IHierarchyItemBase.)
Public propertyCode examplePath
Unique item path in the repository relative to storage root.
(Inherited from IHierarchyItemBase.)
Top
Methods
  NameDescription
Public methodCode exampleCopyToAsync
Creates a copy of this item with a new name in the destination folder.
(Inherited from IHierarchyItem.)
Public methodCode exampleCreateFileAsync
Creates new WebDAV file with the specified name in this folder.
(Inherited from IFolder.)
Public methodCode exampleCreateFolderAsync
Creates new WebDAV folder with the specified name in this folder.
(Inherited from IFolder.)
Public methodCode exampleDeleteAsync
Deletes this item.
(Inherited from IHierarchyItem.)
Public methodCode exampleGetChildrenAsync
Gets direct children of this folder.
(Inherited from IItemCollection.)
Public methodCode exampleGetPropertiesAsync
Gets values of all properties or selected properties for this item.
(Inherited from IHierarchyItem.)
Public methodCode exampleGetPropertyNamesAsync
Gets names of all properties for this item.
(Inherited from IHierarchyItem.)
Public methodCode exampleMoveToAsync
Moves this item to the destination folder under a new name.
(Inherited from IHierarchyItem.)
Public methodMultiGetAsync
Returns a list of business card files that correspont to the specified list of item paths.
(Inherited from IAddressbookReport.)
Public methodQueryAsync
Returns a list of business card files that match specified filter.
(Inherited from IAddressbookReport.)
Public methodCode exampleUpdatePropertiesAsync
Adds, modifies and removes properties for this item.
(Inherited from IHierarchyItem.)
Top
Remarks
Items of this type represent folder that contain business card files. An address book folder can contain business card files (items that implement ICardFile) and folders that are NOT IAddressbookFolder folders. "Nesting" of address book folders within other address book folders at any depth is NOT allowed. http://tools.ietf.org/html/rfc6352#section-5.2
Examples

The code below is part of 'CardDAVServer.SqlStorage.AspNet' C# & VB samples provided with the SDK.

public class AddressbookFolder : DavHierarchyItem, IAddressbookFolder, ICurrentUserPrincipal, IAclHierarchyItem
{
    public static async Task<IAddressbookFolder> LoadByIdAsync(DavContext context, Guid addressbookFolderId)
    {
        // Load only address book that the use has access to. 
        // Also load complete ACL for this address book.
        string sql =
            @"SELECT * FROM [card_AddressbookFolder] 
              WHERE [AddressbookFolderId] = @AddressbookFolderId
              AND [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)

            ; SELECT * FROM [card_Access]
              WHERE [AddressbookFolderId] = @AddressbookFolderId
              AND [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)";

        return (await LoadAsync(context, sql,
              "@UserId"             , context.UserId
            , "@AddressbookFolderId", addressbookFolderId
            )).FirstOrDefault();
    }

    public static async Task<IEnumerable<IAddressbookFolder>> LoadAllAsync(DavContext context)
    {
        // Load only address books that the use has access to. 
        // Also load complete ACL for each address book, but only if user has access to that address book.
        string sql =
            @"SELECT * FROM [card_AddressbookFolder] 
              WHERE [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)

            ; SELECT * FROM [card_Access] 
              WHERE [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)";

        return await LoadAsync(context, sql, "@UserId", context.UserId);
    }

    private static async Task<IEnumerable<IAddressbookFolder>> LoadAsync(DavContext context, string sql, params object[] prms)
    {
        IList<IAddressbookFolder> addressbookFolders = new List<IAddressbookFolder>();

        using (SqlDataReader reader = await context.ExecuteReaderAsync(sql, prms))            
        {
            DataTable addressbooks = new DataTable();
            addressbooks.Load(reader);

            DataTable access = new DataTable();
            access.Load(reader);

            foreach (DataRow rowAddressbookFolder in addressbooks.Rows)
            {
                Guid addressbookFolderId = rowAddressbookFolder.Field<Guid>("AddressbookFolderId");

                string filter = string.Format("AddressbookFolderId = '{0}'", addressbookFolderId);
                DataRow[] rowsAccess = access.Select(filter);

                addressbookFolders.Add(new AddressbookFolder(context, addressbookFolderId, rowAddressbookFolder, rowsAccess));
            }
        }

        return addressbookFolders;
    }

    internal static async Task<IAddressbookFolder> CreateAddressbookFolderAsync(DavContext context, string name, string description)
    {
        // 1. Create address book.
        // 2. Grant owner privileges to the user on the created address book(s).
        string sql = @"INSERT INTO [card_AddressbookFolder] (
                      [AddressbookFolderId]
                    , [Name]
                    , [Description]
                ) VALUES (
                      @AddressbookFolderId
                    , @Name
                    , @Description
                )
                ; INSERT INTO [card_Access] (
                      [AddressbookFolderId]
                    , [UserId]
                    , [Owner]
                    , [Read]
                    , [Write]
                ) VALUES (
                      @AddressbookFolderId
                    , @UserId
                    , @Owner
                    , @Read
                    , @Write
                )";

        Guid addressbookFolderId = Guid.NewGuid();

        await context.ExecuteNonQueryAsync(sql,
              "@AddressbookFolderId", addressbookFolderId
            , "@Name"               , name
            , "@Description"        , description
            , "@UserId"             , context.UserId
            , "@Owner"              , true
            , "@Read"               , true
            , "@Write"              , true
            );
        return await LoadByIdAsync(context, addressbookFolderId);
    }

    private readonly Guid addressbookFolderId;

    private readonly DataRow rowAddressbookFolder;

    private readonly DataRow[] rowsAccess;

    public override string Name
    {
        get { return rowAddressbookFolder != null ? rowAddressbookFolder.Field<string>("Name") : null; }
    }

    public override string Path
    {
        get
        {
            return string.Format("{0}{1}/", AddressbooksRootFolder.AddressbooksRootFolderPath, addressbookFolderId);
        }
    }

    private AddressbookFolder(DavContext context, Guid addressbookFolderId, DataRow addressbook, DataRow[] rowsAccess)
        : base(context)
    {
        this.addressbookFolderId    = addressbookFolderId;
        this.rowAddressbookFolder   = addressbook;
        this.rowsAccess             = rowsAccess;
    }

    public async Task<IEnumerable<ICardFile>> MultiGetAsync(IEnumerable<string> pathList, IEnumerable<PropertyName> propNames)
    {
        // Get list of file names from path list.
        IEnumerable<string> fileNames = pathList.Select(a => System.IO.Path.GetFileNameWithoutExtension(a));

        return await CardFile.LoadByFileNamesAsync(Context, fileNames, PropsToLoad.All);
    }

    public async Task<IEnumerable<ICardFile>> QueryAsync(string rawQuery, IEnumerable<PropertyName> propNames)
    {
        // For the sake of simplicity we just call GetChildren returning all items. 
        // Typically you will return only items that match the query.
        return (await GetChildrenAsync(propNames.ToList(), null, null, null)).Page.Cast<ICardFile>();
    }

    public string AddressbookDescription 
    {
        get { return rowAddressbookFolder.Field<string>("Description"); }
    }

    public async Task<PageResults> GetChildrenAsync(IList<PropertyName> propNames, long? offset, long? nResults, IList<OrderProperty> orderProps)
    {
        // Here we enumerate all business cards contained in this address book.
        // You can filter children items in this implementation and 
        // return only items that you want to be available for this 
        // particular user.

        // Typically only getcontenttype and getetag properties are requested in GetChildren call by CalDAV/CardDAV clients.
        // The iCalendar/vCard (calendar-data/address-data) is typically requested not in GetChildren, but in a separate multiget 
        // report, in MultiGetAsync() method call, that follows this request.

        // Bynari submits PROPFIND without props - Engine will request getcontentlength

        IList<IHierarchyItem> children = new List<IHierarchyItem>();
        return new PageResults((await CardFile.LoadByAddressbookFolderIdAsync(Context, addressbookFolderId, PropsToLoad.Minimum)), null);
    }

    public async Task<IFile> CreateFileAsync(string name, Stream content, string contentType, long totalFileSize)
    {
        // The actual business card file is created in datatbase in CardFile.Write call.
        string fileName = System.IO.Path.GetFileNameWithoutExtension(name);
        return CardFile.CreateCardFile(Context, addressbookFolderId, fileName);
    }

    public async Task<IFolder> CreateFolderAsync(string name)
    {
        throw new DavException("Not allowed.", DavStatus.NOT_ALLOWED);
    }

    public override async Task MoveToAsync(IItemCollection destFolder, string destName, MultistatusException multistatus)
    {
        // Here we support only addressbooks renaming. Check that user has permissions to write.
        string sql = @"UPDATE [card_AddressbookFolder] SET Name=@Name 
            WHERE [AddressbookFolderId]=@AddressbookFolderId
            AND [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId AND [Write] = 1)";

        if (await Context.ExecuteNonQueryAsync(sql, 
              "@Name"               , destName
            , "@UserId"             , Context.UserId
            , "@AddressbookFolderId", addressbookFolderId) < 1)
        {
            throw new DavException("Item not found or you do not have enough permissions to complete this operation.", DavStatus.FORBIDDEN);
        }
    }

    public override async Task DeleteAsync(MultistatusException multistatus)
    {
        // Delete address book and all vCards associated with it. Check that user has permissions to delete.
        string sql = @"DELETE FROM [card_AddressbookFolder] 
            WHERE [AddressbookFolderId]=@AddressbookFolderId
            AND [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId AND [Owner] = 1)";

        if (await Context.ExecuteNonQueryAsync(sql,
              "@UserId"             , Context.UserId
            , "@AddressbookFolderId", addressbookFolderId) < 1)
        {
            throw new DavException("Item not found or you do not have enough permissions to complete this operation.", DavStatus.FORBIDDEN);
        }
    }

    public override async Task<IEnumerable<PropertyValue>> GetPropertiesAsync(IList<PropertyName> names, bool allprop)
    {
        IList<PropertyValue> propVals = await GetPropertyValuesAsync(
                "SELECT [Name], [Namespace], [PropVal] FROM [card_AddressbookFolderProperty] WHERE [AddressbookFolderId] = @AddressbookFolderId",
                "@AddressbookFolderId", addressbookFolderId);

        if (allprop)
        {
            return propVals;
        }
        else
        {
            IList<PropertyValue> requestedPropVals = new List<PropertyValue>();
            foreach (PropertyValue p in propVals)
            {
                if (names.Contains(p.QualifiedName))
                {
                    requestedPropVals.Add(p);
                }
            }
            return requestedPropVals;
        }
    }

    public override async Task UpdatePropertiesAsync(
        IList<PropertyValue> setProps,
        IList<PropertyName> delProps,
        MultistatusException multistatus)
    {
        foreach (PropertyValue p in setProps)
        {
            await SetPropertyAsync(p); // create or update property
        }

        foreach (PropertyName p in delProps)
        {
            await RemovePropertyAsync(p.Name, p.Namespace);
        }
    }

    private async Task<IList<PropertyValue>> GetPropertyValuesAsync(string command, params object[] prms)
    {
        List<PropertyValue> l = new List<PropertyValue>();

        using (SqlDataReader reader = await Context.ExecuteReaderAsync(command, prms))            
        {
            while (reader.Read())
            {
                string name = reader.GetString(reader.GetOrdinal("Name"));
                string ns = reader.GetString(reader.GetOrdinal("Namespace"));
                string value = reader.GetString(reader.GetOrdinal("PropVal"));
                l.Add(new PropertyValue(new PropertyName(name, ns), value));
            }
        }

        return l;
    }

    private async Task SetPropertyAsync(PropertyValue prop)
    {
        string selectCommand =
            @"SELECT Count(*) FROM [card_AddressbookFolderProperty]
              WHERE [AddressbookFolderId] = @AddressbookFolderId AND [Name] = @Name AND [Namespace] = @Namespace";

        int count = await Context.ExecuteScalarAsync<int>(
            selectCommand,
            "@AddressbookFolderId"  , addressbookFolderId,
            "@Name"                 , prop.QualifiedName.Name,
            "@Namespace"            , prop.QualifiedName.Namespace);

        // insert
        if (count == 0)
        {
            string insertCommand = @"INSERT INTO [card_AddressbookFolderProperty] ([AddressbookFolderId], [Name], [Namespace], [PropVal])
                                      VALUES(@AddressbookFolderId, @Name, @Namespace, @PropVal)";

            await Context.ExecuteNonQueryAsync(
                insertCommand,
                "@PropVal"              , prop.Value,
                "@AddressbookFolderId"  , addressbookFolderId,
                "@Name"                 , prop.QualifiedName.Name,
                "@Namespace"            , prop.QualifiedName.Namespace);
        }
        else
        {
            // update
            string command = @"UPDATE [card_AddressbookFolderProperty]
                  SET [PropVal] = @PropVal
                  WHERE [AddressbookFolderId] = @AddressbookFolderId AND [Name] = @Name AND [Namespace] = @Namespace";

            await Context.ExecuteNonQueryAsync(
                command,
                "@PropVal"              , prop.Value,
                "@AddressbookFolderId"  , addressbookFolderId,
                "@Name"                 , prop.QualifiedName.Name,
                "@Namespace"            , prop.QualifiedName.Namespace);
        }
    }

    private async Task RemovePropertyAsync(string name, string ns)
    {
        string command = @"DELETE FROM [card_AddressbookFolderProperty]
                          WHERE [AddressbookFolderId] = @AddressbookFolderId
                          AND [Name] = @Name
                          AND [Namespace] = @Namespace";

        await Context.ExecuteNonQueryAsync(
            command,
            "@AddressbookFolderId"  , addressbookFolderId,
            "@Name"                 , name,
            "@Namespace"            , ns);
    }

    public Task SetOwnerAsync(IPrincipal value)
    {
        throw new DavException("Not implemented.", DavStatus.NOT_IMPLEMENTED);
    }

    public async Task<IPrincipal> GetOwnerAsync()
    {
        DataRow rowOwner = rowsAccess.FirstOrDefault(x => x.Field<bool>("Owner") == true);
        if (rowOwner == null)
            return null;

        return await Acl.User.GetUserAsync(Context, rowOwner.Field<string>("UserId"));
    }

    public Task SetGroupAsync(IPrincipal value)
    {
        throw new DavException("Group cannot be set", DavStatus.FORBIDDEN);
    }

    public async Task<IPrincipal> GetGroupAsync()
    {
        return null; // Groups are not supported.
    }

    public async Task<IEnumerable<SupportedPrivilege>> GetSupportedPrivilegeSetAsync()
    {
        return new[] {
            new SupportedPrivilege
            {
                Privilege = Privilege.Read, IsAbstract = false, DescriptionLanguage = "en",
                Description = "Allows or denies the user the ability to read content and properties of files/folders."
            },
            new SupportedPrivilege
            {
                Privilege = Privilege.Write, IsAbstract = false, DescriptionLanguage = "en",
                Description = "Allows or denies locking an item or modifying the content, properties, or membership of a collection."
            }
        };
    }

    public async Task<IEnumerable<Privilege>> GetCurrentUserPrivilegeSetAsync()
    {
        DataRow rowAccess = rowsAccess.FirstOrDefault(x => x.Field<string>("UserId")== Context.UserId);
        if (rowAccess == null)
            return null;

        List<Privilege> privileges = new List<Privilege>();
        if (rowAccess.Field<bool>("Read"))
            privileges.Add(Privilege.Read);

        if (rowAccess.Field<bool>("Write"))
            privileges.Add(Privilege.Write);

        return privileges;
    }

    public async Task<IEnumerable<ReadAce>> GetAclAsync(IList<PropertyName> propertyNames)
    {
        IList<ReadAce> aceList = new List<ReadAce>();
        foreach (DataRow rowAccess in rowsAccess)
        {
            ReadAce ace = new ReadAce();
            ace.Principal = await Acl.User.GetUserAsync(Context, rowAccess.Field<string>("UserId"));
            if (rowAccess.Field<bool>("Read"))
                ace.GrantPrivileges.Add(Privilege.Read);
            if (rowAccess.Field<bool>("Write"))
                ace.GrantPrivileges.Add(Privilege.Write);

            ace.IsProtected = rowAccess.Field<bool>("Owner");
            aceList.Add(ace);
        }
        return aceList;
    }

    public Task SetAclAsync(IList<WriteAce> aces)
    {
        throw new DavException("Not implemented.", DavStatus.NOT_IMPLEMENTED);
    }

    public async Task<AclRestriction> GetAclRestrictionsAsync()
    {
        return new AclRestriction { NoInvert = true, GrantOnly = true };
    }

    public async Task<IEnumerable<IHierarchyItem>> GetInheritedAclSetAsync()
    {
        return new IHierarchyItem[] { };
    }

    public async Task<IEnumerable<IPrincipalFolder>> GetPrincipalCollectionSetAsync()
    {
        return new IPrincipalFolder[] { new Acl.UsersFolder(Context) };
    }

    public async Task<IPrincipal> ResolveWellKnownPrincipalAsync(WellKnownPrincipal wellKnownPrincipal)
    {
        return null;
    }

    public Task<IEnumerable<IAclHierarchyItem>> GetItemsByPropertyAsync(MatchBy matchBy, IList<PropertyName> props)
    {
        throw new DavException("Not implemented.", DavStatus.NOT_IMPLEMENTED);
    }
}
See Also