/// <summary>
        /// Stores IMAP message flags (\seen,\draft, ...).
        /// </summary>
        /// <param name="accessingUser">User who accesses this method. 
        /// User needs r permission to call this method or Exception is thrown. 
        /// There is special user 'system' for which permission check is skipped.</param>
        /// <param name="folderOwnerUser">User who's folder it is.</param>
        /// <param name="folder">Folder which message flags to store. For example: Inbox,Public Folders/Documnets .</param>
        /// <param name="message">Fix ME: ???</param>
        /// <param name="msgFlags">Message flags to store.</param>
        public void StoreMessageFlags(string accessingUser,string folderOwnerUser,string folder,LumiSoft.Net.IMAP.Server.IMAP_Message message,IMAP_MessageFlags msgFlags)
        {
            /* Implementation notes:
                *) Validate values. Throw ArgumnetExcetion if invalid values.
                *) Ensure that user exists.
                *) Normalize folder. Remove '/' from folder start and end, ... .
                *) Do Shared Folders mapping.
                *) Ensure that folder exists. Throw Exception if don't.
                *) Remove all message flags which permissions user doesn't have.
                *) Store message.
            */

            //--- Validate values -------------------//
            ArgsValidator.ValidateUserName(folderOwnerUser);
            ArgsValidator.ValidateFolder(folder);
            ArgsValidator.ValidateNotNull(message);
            //---------------------------------------//

            // Ensure that user exists.
            if(!UserExists(folderOwnerUser)){
                throw new Exception("User '" + folderOwnerUser + "' doesn't exist !");
            }

            // Normalize folder. Remove '/' from folder start and end.
            folder = API_Utlis.NormalizeFolder(folder);

            // Do Shared Folders mapping.
            string originalFolder = folder;
            SharedFolderMapInfo mappedFolder = MapSharedFolder(originalFolder);
            if(mappedFolder.IsSharedFolder){
                folderOwnerUser = mappedFolder.FolderOnwer;
                folder = mappedFolder.Folder;

                if(folderOwnerUser == "" || folder == ""){
                    throw new ArgumentException("Specified root folder '" + originalFolder + "' isn't accessible !");
                }
            }

            // Ensure that folder exists. Throw Exception if don't.
            if(!FolderExists(folderOwnerUser + "/" + folder)){
                throw new Exception("Folder '" + folder + "' doesn't exist !");
            }

            // Remove all message flags which permissions user doesn't have.
            if(accessingUser != "system"){
                IMAP_ACL_Flags userACL = GetUserACL(folderOwnerUser,folder,accessingUser);
                if((userACL & IMAP_ACL_Flags.s) == 0){
                    msgFlags &= ~IMAP_MessageFlags.Seen;
                }
                else if((userACL & IMAP_ACL_Flags.d) == 0){
                    msgFlags &= ~IMAP_MessageFlags.Deleted;
                }
                else if((userACL & IMAP_ACL_Flags.s) == 0){
                    msgFlags &= (~IMAP_MessageFlags.Answered | ~IMAP_MessageFlags.Draft | ~IMAP_MessageFlags.Flagged);
                }
            }

            //--- Store message flags
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_StoreMessageFlags")){
                sqlCmd.AddParameter("_userName"     ,NpgsqlDbType.Varchar,folderOwnerUser);
                sqlCmd.AddParameter("_folder"       ,NpgsqlDbType.Varchar,folder);
                sqlCmd.AddParameter("_messageID"    ,NpgsqlDbType.Varchar,message.ID);
                sqlCmd.AddParameter("_messageFlags" ,NpgsqlDbType.Integer,(int)message.Flags);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Creates new IMAP folder.
        /// </summary>
        /// <param name="accessingUser">User who accesses this method. 
        /// User needs r permission to call this method or Exception is thrown. 
        /// There is special user 'system' for which permission check is skipped.</param>
        /// <param name="folderOwnerUser">User who's folder it is.</param>
        /// <param name="folder">Folder what contains message to copy. For example: Inbox,Public Folders/Documnets .</param>
        public void CreateFolder(string accessingUser,string folderOwnerUser,string folder)
        {
            /* Implementation notes:
                *) Validate values. Throw ArgumnetExcetion if invalid values.
                *) Ensure that user exists.
                *) Normalize folder. Remove '/' from folder start and end, ... .
                *) Do Shared Folders mapping.
                *) Ensure that folder doesn't exists. Throw Exception if don't.
                *) See if user has sufficient permissions. User requires 'c' permission.
                    There is builtin user system, skip ACL for it.
                *) Create folder.
            */

            //--- Validate values -------------------//
            ArgsValidator.ValidateUserName(folderOwnerUser);
            ArgsValidator.ValidateFolder(folder);
            //---------------------------------------//

            // Ensure that user exists.
            if(!UserExists(folderOwnerUser)){
                throw new Exception("User '" + folderOwnerUser + "' doesn't exist !");
            }

            // Normalize folder. Remove '/' from folder start and end.
            folder = API_Utlis.NormalizeFolder(folder);

            // Do Shared Folders mapping.
            string originalFolder = folder;
            SharedFolderMapInfo mappedFolder = MapSharedFolder(originalFolder);
            if(mappedFolder.IsSharedFolder){
                folderOwnerUser = mappedFolder.FolderOnwer;
                folder = mappedFolder.Folder;

                if(folderOwnerUser == "" || folder == ""){
                    throw new ArgumentException("Specified root folder '" + originalFolder + "' isn't accessible !");
                }
            }

            // Ensure that folder doesn't exists. Throw Exception if don't.
            if(FolderExists(folderOwnerUser + "/" + folder)){
                throw new Exception("Folder '" + folder + "' already exist !");
            }

            // See if user has sufficient permissions. User requires 'c' permission.
            //  There is builtin user system, skip ACL for it.
            if(accessingUser.ToLower() != "system"){
                IMAP_ACL_Flags acl = GetUserACL(folderOwnerUser,folder,accessingUser);
                if((acl & IMAP_ACL_Flags.c) == 0){
                    throw new InsufficientPermissionsException("Insufficient permissions for folder '" + accessingUser + "/" + folder + "' !");
                }
            }

            //--- Create folder
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_CreateFolder")){
                sqlCmd.AddParameter("_folderID",NpgsqlDbType.Varchar,Guid.NewGuid().ToString());
                sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,folderOwnerUser);
                sqlCmd.AddParameter("_folder"  ,NpgsqlDbType.Varchar,folder);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Deletes specified filter.
        /// </summary>
        /// <param name="filterID">FilterID of the filter which to delete.</param>
        public void DeleteFilter(string filterID)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_DeleteFilter")){
                sqlCmd.AddParameter("_filterID" ,NpgsqlDbType.Varchar,filterID);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// AAdds new remote pop3 server to user.
        /// </summary>
        /// <param name="serverID">Server ID. Suggested value is Guid.NewGuid() .</param>
        /// <param name="userName">User name. Use <see cref="IMailServerApi.GetUsers">GetUsers()</see> to get valid values.</param>
        /// <param name="description">Remote server description.</param>
        /// <param name="remoteServer">Remote server name.</param>
        /// <param name="remotePort">Remote server port.</param>
        /// <param name="remoteUser">Remote server user name.</param>
        /// <param name="remotePassword">Remote server password.</param>
        /// <param name="useSSL">Specifies if SSL must be used to connect to remote server.</param>
        /// <param name="enabled">Specifies if remote server is enabled.</param>
        /// <remarks>Throws exception if specified user remote server already exists.</remarks>
        public void AddUserRemoteServer(string serverID,string userName,string description,string remoteServer,int remotePort,string remoteUser,string remotePassword,bool useSSL,bool enabled)
        {
            if(serverID.Length == 0){
                throw new Exception("You must specify serverID");
            }
            if(userName.Length == 0){
                throw new Exception("You must specify userName");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddUserRemoteServer")){
                sqlCmd.AddParameter("_serverID"       ,NpgsqlDbType.Varchar,serverID);
                sqlCmd.AddParameter("_userName"       ,NpgsqlDbType.Varchar,userName);
                sqlCmd.AddParameter("_description"    ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_remoteServer"   ,NpgsqlDbType.Varchar,remoteServer);
                sqlCmd.AddParameter("_remotePort"     ,NpgsqlDbType.Integer,remotePort);
                sqlCmd.AddParameter("_remoteUserName" ,NpgsqlDbType.Varchar,remoteUser);
                sqlCmd.AddParameter("_remotePassword" ,NpgsqlDbType.Varchar,remotePassword);
                sqlCmd.AddParameter("_useSSL"         ,NpgsqlDbType.Boolean,useSSL);
                sqlCmd.AddParameter("_enabled"        ,NpgsqlDbType.Boolean,enabled);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Authenticates user.
        /// </summary>
        /// <param name="userName">User name.</param>
        /// <param name="passwData">Password data.</param>
        /// <param name="authData">Authentication specific data(as tag).</param>
        /// <param name="authType">Authentication type.</param>
        /// <returns></returns>
        public DataSet AuthUser(string userName,string passwData,string authData,AuthType authType)
        {
            DataSet retVal = new DataSet();
            DataTable dt = retVal.Tables.Add("Result");
            dt.Columns.Add("Result");
            dt.Columns.Add("ReturnData");
            DataRow drx = dt.NewRow();
            drx["Result"] = "false";
            drx["ReturnData"] = "";
            dt.Rows.Add(drx);

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_GetUserProperties")){
                sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,userName);

                DataSet ds = sqlCmd.Execute();
                ds.Tables[0].TableName = "Users";

                if(ds.Tables["Users"].Rows.Count > 0){
                    string password = ds.Tables["Users"].Rows[0]["PASSWORD"].ToString().ToLower();

                    switch(authType)
                    {
                        case AuthType.APOP:
                            if(AuthHelper.Apop(password,authData) == passwData){
                                drx["Result"] = "true";
                                return retVal;
                            }
                            break;

                        case AuthType.CRAM_MD5:
                            if(AuthHelper.Cram_Md5(password,authData) == passwData){
                                drx["Result"] = "true";
                                return retVal;
                            }
                            break;

                        case AuthType.DIGEST_MD5:
                            string realm      = "";
                            string nonce      = "";
                            string cnonce     = "";
                            string digest_uri = "";
                            foreach(string clntRespParam in authData.Split(',')){
                                if(clntRespParam.StartsWith("realm=")){
                                    realm = clntRespParam.Split(new char[]{'='},2)[1].Replace("\"","");
                                }
                                else if(clntRespParam.StartsWith("nonce=")){
                                    nonce = clntRespParam.Split(new char[]{'='},2)[1].Replace("\"","");
                                }
                                else if(clntRespParam.StartsWith("cnonce=")){
                                    cnonce = clntRespParam.Split(new char[]{'='},2)[1].Replace("\"","");
                                }
                                else if(clntRespParam.StartsWith("digest-uri=")){
                                    digest_uri = clntRespParam.Split(new char[]{'='},2)[1].Replace("\"","");
                                }
                            }

                            if(passwData == AuthHelper.Digest_Md5(true,realm,userName,password,nonce,cnonce,digest_uri)){
                                string returnData = AuthHelper.Digest_Md5(false,realm,userName,password,nonce,cnonce,digest_uri);

                                drx["Result"] = "true";
                                drx["ReturnData"] = returnData;
                                return retVal;
                            }

                            break;

                        case AuthType.Plain:
                            if(password == passwData.ToLower()){
                                drx["Result"] = "true";
                                return retVal;
                            }
                            break;
                    }
                }
            }

            return retVal;
        }
        /// <summary>
        /// Adds new user to specified domain.
        /// </summary>
        /// <param name="userID">User ID. Suggested value is Guid.NewGuid() .</param>
        /// <param name="userName">User login name.</param>
        /// <param name="fullName">User full name.</param> 
        /// <param name="password">User login password.</param>
        /// <param name="description">User description.</param>
        /// <param name="domainName">Domain where to add user. Use <see cref="IMailServerApi.GetDomains">GetDomains()</see> to get valid values.</param>
        /// <param name="mailboxSize">Maximum mailbox size.</param>
        /// <param name="enabled">Sepcifies if user is enabled.</param>
        /// <param name="permissions">Specifies user permissions.</param>
        /// <remarks>Throws exception if specified user already exists.</remarks>
        public void AddUser(string userID,string userName,string fullName,string password,string description,string domainName,int mailboxSize,bool enabled,UserPermissions_enum permissions)
        {
            if(userID.Length == 0){
                throw new Exception("You must specify userID");
            }
            if(userName.Length == 0){
                throw new Exception("You must specify userName");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddUser")){
                sqlCmd.AddParameter("_userID"      ,NpgsqlDbType.Varchar,userID);
                sqlCmd.AddParameter("_fullName"    ,NpgsqlDbType.Varchar,fullName);
                sqlCmd.AddParameter("_userName"    ,NpgsqlDbType.Varchar,userName);
                sqlCmd.AddParameter("_password"    ,NpgsqlDbType.Varchar,password);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_domainName"  ,NpgsqlDbType.Varchar,domainName);
                sqlCmd.AddParameter("_mailboxSize" ,NpgsqlDbType.Integer,mailboxSize);
                sqlCmd.AddParameter("_enabled"     ,NpgsqlDbType.Boolean,enabled);
                sqlCmd.AddParameter("_permissions" ,NpgsqlDbType.Integer,permissions);

                DataSet ds = sqlCmd.Execute();
                ds.Tables[0].TableName = "Users";
            }
        }
        /// <summary>
        /// Adds new user message rule.
        /// </summary>
        /// <param name="userID">User who owns specified rule.</param>
        /// <param name="ruleID">Rule ID. Guid.NewID().ToString() is suggested.</param>
        /// <param name="cost">Cost specifies in what order rules are processed. Costs with lower values are processed first.</param>
        /// <param name="enabled">Specifies if rule is enabled.</param>
        /// <param name="checkNextRule">Specifies when next rule is checked.</param>
        /// <param name="description">Rule description.</param>
        /// <param name="matchExpression">Rule match expression.</param>
        public void AddUserMessageRule(string userID,string ruleID,long cost,bool enabled,GlobalMessageRule_CheckNextRule_enum checkNextRule,string description,string matchExpression)
        {
            if(userID == null || userID == ""){
                throw new Exception("Invalid userID value, userID can't be '' or null !");
            }
            if(ruleID == null || ruleID == ""){
                throw new Exception("Invalid ruleID value, ruleID can't be '' or null !");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddUserMessageRule")){
                sqlCmd.AddParameter("_userID"          ,NpgsqlDbType.Varchar,userID);
                sqlCmd.AddParameter("_ruleID"          ,NpgsqlDbType.Varchar,ruleID);
                sqlCmd.AddParameter("_cost"            ,NpgsqlDbType.Bigint  ,cost);
                sqlCmd.AddParameter("_enabled"         ,NpgsqlDbType.Boolean ,enabled);
                sqlCmd.AddParameter("_checkNextRule"   ,NpgsqlDbType.Integer ,checkNextRule);
                sqlCmd.AddParameter("_description"     ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_matchExpression" ,NpgsqlDbType.Bytea   ,System.Text.Encoding.Default.GetBytes(matchExpression));

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Updates specified mailing list.
        /// </summary>
        /// <param name="mailingListID">Mailing list ID.</param>
        /// <param name="mailingListName">Mailing list name name. Use <see cref="IMailServerApi.GetMailingLists">GetMailingLists()</see> to get valid values.</param>
        /// <param name="description">Mailing list description.</param>
        /// <param name="domainName">Domain name. Use <see cref="IMailServerApi.GetDomains">>GetUsers()</see> to get valid values.</param>
        /// <param name="enabled">Specifies if mailing list is enabled.</param>
        public void UpdateMailingList(string mailingListID,string mailingListName,string description,string domainName,bool enabled)
        {
            if(mailingListName.Length == 0){
                throw new Exception("You must specify mailingListName");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateMailingList")){
                sqlCmd.AddParameter("_mailingListID"   ,NpgsqlDbType.Varchar,mailingListID);
                sqlCmd.AddParameter("_mailingListName" ,NpgsqlDbType.Varchar,mailingListName);
                sqlCmd.AddParameter("_description"     ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_domainName"      ,NpgsqlDbType.Varchar,domainName);
                sqlCmd.AddParameter("_enabled"         ,NpgsqlDbType.Boolean,enabled);

                DataSet ds = sqlCmd.Execute();
            }
        }
 /// <summary>
 /// Updates recycle bin settings.
 /// </summary>
 /// <param name="deleteToRecycleBin">Specifies if deleted messages are store to recycle bin.</param>
 /// <param name="deleteMessagesAfter">Specifies how old messages will be deleted.</param>
 public void UpdateRecycleBinSettings(bool deleteToRecycleBin,int deleteMessagesAfter)
 {
     using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateRecycleBinSettings")){
         sqlCmd.AddParameter("_deleteToRecycleBin" ,NpgsqlDbType.Boolean,deleteToRecycleBin);
         sqlCmd.AddParameter("_deleteMessagesAfter",NpgsqlDbType.Integer,deleteMessagesAfter);
         DataSet ds = sqlCmd.Execute();
     }
 }
        /// <summary>
        /// Updates specified filter.
        /// </summary>		
        /// <param name="filterID">FilterID which to update.</param>
        /// <param name="description">Filter description</param>
        /// <param name="type">Filter type. Eg. ISmtpMessageFilter.</param>
        /// <param name="assembly">Assembly with full location. Eg. C:\MailServer\Filters\filter.dll .</param>
        /// <param name="className">Filter full class name, wih namespace. Eg. LumiSoft.MailServer.Fileters.Filter1 .</param>
        /// <param name="cost">Filters are sorted by cost and proccessed with cost value. Smallest cost is proccessed first.</param>
        /// <param name="enabled">Specifies if filter is enabled.</param>
        /// <returns></returns>
        public void UpdateFilter(string filterID,string description,string type,string assembly,string className,long cost,bool enabled)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateFilter")){
                sqlCmd.AddParameter("_filterID"    ,NpgsqlDbType.Varchar,filterID);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_type"        ,NpgsqlDbType.Varchar,type);
                sqlCmd.AddParameter("_assembly"    ,NpgsqlDbType.Varchar,assembly);
                sqlCmd.AddParameter("_className"   ,NpgsqlDbType.Varchar,className);
                sqlCmd.AddParameter("_cost"        ,NpgsqlDbType.Bigint ,cost);
                sqlCmd.AddParameter("_enabled"     ,NpgsqlDbType.Boolean,enabled);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Updates user group info.
        /// </summary>
        /// <param name="groupID">Group ID.</param>
        /// <param name="groupName">Group name.</param>
        /// <param name="description">Group description.</param>
        /// <param name="enabled">Specifies if group is enabled.</param>
        public void UpdateGroup(string groupID,string groupName,string description,bool enabled)
        {
            /* Implementation notes:
                *) Validate values. Throw ArgumnetExcetion if invalid values.
                *) Ensure that group with specified ID does exist.  Throw Exception if doesn't.
                *) If group name is changed, ensure that new group name won't conflict
                   any other group or user name. Throw Exception if does.
                *) Udpate group.
            */

            //--- Validate values --------------------//
            if(groupID == null || groupID == ""){
                throw new Exception("Invalid groupID value, groupID can't be '' or null !");
            }
            ArgsValidator.ValidateUserName(groupName);
            ArgsValidator.ValidateNotNull(description);
            //----------------------------------------//

            /* We handle these is SQL, sql throws Excption

            *) Ensure that group with specified ID does exist.  Throw Exception if doesn't.
            *) If group name is changed, ensure that new group name won't conflict
               any other group or user name. Throw Exception if does.
            */

            // Update group
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateGroup")){
                sqlCmd.AddParameter("_groupID"     ,NpgsqlDbType.Varchar,groupID);
                sqlCmd.AddParameter("_groupName"   ,NpgsqlDbType.Varchar,groupName);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_enabled"     ,NpgsqlDbType.Boolean,enabled);

                DataSet ds = sqlCmd.Execute();
                ds.Tables[0].TableName = "Groups";
            }
        }
        /// <summary>
        /// Updates specified domain data.
        /// </summary>
        /// <param name="domainID">Domain ID which to update.</param>
        /// <param name="domainName">Domain name.</param>
        /// <param name="description">Domain description.</param>
        public void UpdateDomain(string domainID,string domainName,string description)
        {
            if(domainID.Length == 0){
                throw new Exception("You must specify domainID");
            }
            ArgsValidator.ValidateDomainName(domainName);

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateDomain")){
                sqlCmd.AddParameter("_domainID"   ,NpgsqlDbType.Varchar,domainID);
                sqlCmd.AddParameter("_domainName" ,NpgsqlDbType.Varchar,domainName);
                sqlCmd.AddParameter("_description",NpgsqlDbType.Varchar,description);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// UnSubscribes IMAP folder.
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="folder"></param>
        public void UnSubscribeFolder(string userName,string folder)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UnSubscribeFolder")){
                sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,userName);
                sqlCmd.AddParameter("_folder"  ,NpgsqlDbType.Varchar,folder);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Add new email address to specified mailing list.
        /// </summary>
        /// <param name="addressID">Address ID. Suggested value is Guid.NewGuid() .</param>
        /// <param name="mailingListName">Mailing list name name. Use <see cref="IMailServerApi.GetMailingLists">GetMailingLists()</see> to get valid values.</param>
        /// <param name="address">Mailing list member address.</param>
        /// <remarks>Throws exception if specified mailing list member already exists.</remarks>
        public void AddMailingListAddress(string addressID,string mailingListName,string address)
        {
            if(addressID.Length == 0){
                throw new Exception("You must specify addressID");
            }
            if(mailingListName.Length == 0){
                throw new Exception("You must specify mailingListName");
            }
            if(address.Length == 0){
                throw new Exception("You must specify address");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddMailingListAddress")){
                sqlCmd.AddParameter("_addressID"       ,NpgsqlDbType.Varchar,addressID);
                sqlCmd.AddParameter("_mailingListName" ,NpgsqlDbType.Varchar,mailingListName);
                sqlCmd.AddParameter("_address"         ,NpgsqlDbType.Varchar,address);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Adds new IP security entry.
        /// </summary>
        /// <param name="id">IP security entry ID.</param>
        /// <param name="enabled">Specifies if IP security entry is enabled.</param>
        /// <param name="description">IP security entry description text.</param>
        /// <param name="service">Specifies service for what security entry applies.</param>
        /// <param name="action">Specifies what action done if IP matches to security entry range.</param>
        /// <param name="startIP">Range start IP.</param>
        /// <param name="endIP">Range end IP.</param>
        public void AddSecurityEntry(string id,bool enabled,string description,Service_enum service,IPSecurityAction_enum action,IPAddress startIP,IPAddress endIP)
        {
            if(id.Length == 0){
                throw new Exception("You must specify securityID");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddSecurityEntry")){
                sqlCmd.AddParameter("_id"          ,NpgsqlDbType.Varchar,id);
                sqlCmd.AddParameter("_enabled"     ,NpgsqlDbType.Boolean,enabled);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_service"     ,NpgsqlDbType.Integer,(int)service);
                sqlCmd.AddParameter("_action"      ,NpgsqlDbType.Integer,(int)action);
                sqlCmd.AddParameter("_startIP"     ,NpgsqlDbType.Varchar,startIP.ToString());
                sqlCmd.AddParameter("_endIP"       ,NpgsqlDbType.Varchar,endIP.ToString());

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Updates IP security entry.
        /// </summary>
        /// <param name="id">IP security entry ID.</param>
        /// <param name="enabled">Specifies if IP security entry is enabled.</param>
        /// <param name="description">IP security entry description text.</param>
        /// <param name="service">Specifies service for what security entry applies.</param>
        /// <param name="action">Specifies what action done if IP matches to security entry range.</param>
        /// <param name="startIP">Range start IP.</param>
        /// <param name="endIP">Range end IP.</param>
        public void UpdateSecurityEntry(string id,bool enabled,string description,Service_enum service,IPSecurityAction_enum action,IPAddress startIP,IPAddress endIP)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateSecurityEntry")){
                sqlCmd.AddParameter("_id"          ,NpgsqlDbType.Varchar,id);
                sqlCmd.AddParameter("_enabled"     ,NpgsqlDbType.Boolean,enabled);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_service"     ,NpgsqlDbType.Integer,(int)service);
                sqlCmd.AddParameter("_action"      ,NpgsqlDbType.Integer,(int)action);
                sqlCmd.AddParameter("_startIP"     ,NpgsqlDbType.Varchar,startIP.ToString());
                sqlCmd.AddParameter("_endIP"       ,NpgsqlDbType.Varchar,endIP.ToString());

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Add shared folder root.
        /// </summary>
        /// <param name="rootID">Root folder ID. Guid.NewID().ToString() is suggested.</param>
        /// <param name="enabled">Specifies if root folder is enabled.</param>
        /// <param name="folder">Folder name which will be visible to public.</param>
        /// <param name="description">Description text.</param>
        /// <param name="rootType">Specifies what type root folder is.</param>
        /// <param name="boundedUser">User which to bound root folder.</param>
        /// <param name="boundedFolder">Folder which to bound to public folder.</param>
        public void AddSharedFolderRoot(string rootID,bool enabled,string folder,string description,SharedFolderRootType_enum rootType,string boundedUser,string boundedFolder)
        {
            /* Implementation notes:
                *) Validate values. Throw ArgumnetExcetion if invalid values.
                *) Ensure that root ID doesn't exists.
                *) Ensure that root doesn't exists.
                *) Add root folder.
            */

            if(rootID == null || rootID == ""){
                throw new Exception("Invalid rootID value, rootID can't be '' or null !");
            }

            //--- Validate values -------------------------------------//
            ArgsValidator.ValidateNotNull(rootID);
            ArgsValidator.ValidateSharedFolderRoot(folder);
            ArgsValidator.ValidateNotNull(description);
            if(rootType == SharedFolderRootType_enum.BoundedRootFolder){
                ArgsValidator.ValidateUserName(boundedUser);
                ArgsValidator.ValidateFolder(boundedFolder);
            }
            //---------------------------------------------------------//

            /* We handle these is SQL, sql returns these errors in ErrorText

                *) Ensure that root ID doesn't exists.
                *) Ensure that root doesn't exists.
            */

            // Insert group
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddSharedFolderRoot")){
                sqlCmd.AddParameter("_rootID"        ,NpgsqlDbType.Varchar,rootID);
                sqlCmd.AddParameter("_enabled"       ,NpgsqlDbType.Boolean,enabled);
                sqlCmd.AddParameter("-folder"        ,NpgsqlDbType.Varchar,folder);
                sqlCmd.AddParameter("_description"   ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_rootType"      ,NpgsqlDbType.Integer,rootType);
                sqlCmd.AddParameter("_boundedUser"   ,NpgsqlDbType.Varchar,boundedUser);
                sqlCmd.AddParameter("_boundedFolder" ,NpgsqlDbType.Varchar,boundedFolder);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Updates server settings.
        /// </summary>
        public void UpdateSettings(DataRow settings)
        {
            /*
            DataRow row = GetSettings();
            foreach(DataColumn dc in row.Table.Columns){
                row[dc.ColumnName] = settings[dc.ColumnName];
            }*/

            using(MemoryStream strm = new MemoryStream()){
                settings.Table.DataSet.WriteXml(strm);

                using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateSettings")){
                    sqlCmd.AddParameter("_settings" ,NpgsqlDbType.Bytea,strm.ToArray());

                    DataSet ds = sqlCmd.Execute();
                }
            }
        }
        /// <summary>
        /// Add new email address to user.
        /// </summary>
        /// <param name="userName">User name. Use <see cref="IMailServerApi.GetUsers">>GetUsers()</see> to get valid values.</param>
        /// <param name="emailAddress">Email address to add.</param>
        /// <remarks>Throws exception if specified user email address exists.</remarks>
        public void AddUserAddress(string userName,string emailAddress)
        {
            if(userName.Length == 0){
                throw new Exception("You must specify userName");
            }
            if(emailAddress.Length == 0){
                throw new Exception("You must specify address");
            }
            if(emailAddress.IndexOf('@') == -1){
                throw new Exception("Invalid email address, @ is missing !");
            }

            string[] localPart_domain = emailAddress.Split('@');

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddEmailAddress")){
                sqlCmd.AddParameter("_localPart" ,NpgsqlDbType.Varchar,localPart_domain[0]);
                sqlCmd.AddParameter("_domainName",NpgsqlDbType.Varchar,localPart_domain[1]);
                sqlCmd.AddParameter("_OwnerID"   ,NpgsqlDbType.Varchar,GetUserID(userName));

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Adds new route.
        /// </summary>
        /// <param name="routeID">Route ID.</param>
        /// <param name="cost">Cost specifies in what order roues are processed. Costs with lower values are processed first.</param>
        /// <param name="enabled">Specifies if route is enabled.</param>
        /// <param name="description">Route description text.</param>
        /// <param name="pattern">Match pattern. For example: *,*@domain.com,*[email protected].</param>
        /// <param name="action">Specifies route action.</param>
        /// <param name="actionData">Route action data.</param>
        public void AddRoute(string routeID,long cost,bool enabled,string description,string pattern,RouteAction_enum action,byte[] actionData)
        {
            if(routeID.Length == 0){
                throw new Exception("You must specify routeID");
            }
            if(pattern.Length == 0){
                throw new Exception("You must specify pattern");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddRoute")){
                sqlCmd.AddParameter("_routeID"     ,NpgsqlDbType.Varchar,routeID);
                sqlCmd.AddParameter("_cost"        ,NpgsqlDbType.Bigint ,cost);
                sqlCmd.AddParameter("_enabled"     ,NpgsqlDbType.Boolean,enabled);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_pattern"     ,NpgsqlDbType.Varchar,pattern);
                sqlCmd.AddParameter("_action"      ,NpgsqlDbType.Integer,action);
                sqlCmd.AddParameter("_actionData"  ,NpgsqlDbType.Bytea  ,actionData);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Adds action to specified user message rule.
        /// </summary>
        /// <param name="userID">User who owns specified rule.</param>
        /// <param name="ruleID">Rule ID to which to add this action.</param>
        /// <param name="actionID">Action ID. Guid.NewID().ToString() is suggested.</param>
        /// <param name="description">Action description.</param>
        /// <param name="actionType">Action type.</param>
        /// <param name="actionData">Action data. Data structure depends on action type.</param>
        public void AddUserMessageRuleAction(string userID,string ruleID,string actionID,string description,GlobalMessageRuleAction_enum actionType,byte[] actionData)
        {
            if(userID == null || userID == ""){
                throw new Exception("Invalid userID value, userID can't be '' or null !");
            }
            if(ruleID == null || ruleID == ""){
                throw new Exception("Invalid ruleID value, ruleID can't be '' or null !");
            }
            if(actionID == null || actionID == ""){
                throw new Exception("Invalid actionID value, actionID can't be '' or null !");
            }

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddUserMessageRuleAction")){
                sqlCmd.AddParameter("_userID"      ,NpgsqlDbType.Varchar,userID);
                sqlCmd.AddParameter("_ruleID"      ,NpgsqlDbType.Varchar,ruleID);
                sqlCmd.AddParameter("_actionID"    ,NpgsqlDbType.Varchar,actionID);
                sqlCmd.AddParameter("_description" ,NpgsqlDbType.Varchar,description);
                sqlCmd.AddParameter("_actionType"  ,NpgsqlDbType.Integer,(int)actionType);
                sqlCmd.AddParameter("_actionData"  ,NpgsqlDbType.Bytea  ,actionData);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Updates user last login time.
        /// </summary>
        /// <param name="userName">User name who's last login time to update.</param>
        public void UpdateUserLastLoginTime(string userName)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_UpdateUserLastLoginTime")){
                sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,userName);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Adds users default folder.
        /// </summary>
        /// <param name="folderName">Folder name.</param>
        /// <param name="permanent">Spcifies if folder is permanent, user can't delete it.</param>
        public void AddUsersDefaultFolder(string folderName,bool permanent)
        {
            ArgsValidator.ValidateFolder(folderName);

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_AddUsersDefaultFolder")){
                sqlCmd.AddParameter("_folderName" ,NpgsqlDbType.Varchar,folderName);
                sqlCmd.AddParameter("_permanent  ",NpgsqlDbType.Boolean ,permanent);

                DataSet ds = sqlCmd.Execute();
                ds.Tables[0].TableName = "UsersDefaultFolders";
            }
        }
        /// <summary>
        /// Checks if user exists.
        /// </summary>
        /// <param name="userName">User name.</param>
        /// <returns>Returns true if user exists.</returns>
        public bool UserExists(string userName)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_GetUserProperties")){
                sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,userName);

                DataSet ds = sqlCmd.Execute();
                ds.Tables[0].TableName = "Users";

                if(ds.Tables["Users"].Rows.Count > 0){
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Checks if specified user can access specified mailing list.
        /// There is one built-in user anyone, that represent all users (including anonymous).
        /// </summary>
        /// <param name="mailingListName">Mailing list name.</param>
        /// <param name="user">User name.</param>
        /// <returns></returns>
        public bool CanAccessMailingList(string mailingListName,string user)
        {
            /* Implementation notes:
                *) Ensure that mailing list exists.
                *) Check access.
            */

            // Ensure that mailing list exists
            // Get mailing list ID
            string mailingListID = null;
            foreach(DataRowView drV in GetMailingLists("ALL")){
                if(drV["MailingListName"].ToString().ToLower() == mailingListName.ToLower()){
                    mailingListID = drV["MailingListID"].ToString();
                    break;
                }
            }
            if(mailingListID == null){
                throw new Exception("Invalid mailing list name, specified mailing list '" + mailingListName + "' doesn't exist !");
            }

            // Check access
            WSqlCommand cmd = new WSqlCommand(m_ConStr,"select * from lsMailingListACL");
            cmd.CommandType = CommandType.Text;
            DataSet dsMailingListACL = cmd.Execute();
            dsMailingListACL.Tables[0].TableName = "ACL";

            foreach(DataRow dr in dsMailingListACL.Tables["ACL"].Rows){
                if(dr["MailingListID"].ToString() == mailingListID){
                    // Built-in anyone
                    if(dr["UserOrGroup"].ToString().ToLower() == "anyone"){
                        return true;
                    }
                    // Built-in "authenticated users"
                    else if(dr["UserOrGroup"].ToString().ToLower() == "authenticated users"){
                        return UserExists(user);
                    }
                    // User or group
                    else{
                        if(GroupExists(dr["UserOrGroup"].ToString())){
                            return IsUserGroupMember(dr["UserOrGroup"].ToString(),user);
                        }
                        else{
                            return UserExists(user);
                        }
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// Checks if specified mailbox size is exceeded.
        /// </summary>
        /// <param name="userName">User name. Use <see cref="IMailServerApi.GetUsers">GetUsers()</see> to get valid values.</param>
        /// <returns>Returns true if exceeded.</returns>
        public bool ValidateMailboxSize(string userName)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_ValidateMailboxSize")){
                sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,userName);

                DataSet ds = sqlCmd.Execute();
                return (bool)sqlCmd.ExecuteScalar();
            }
        }
        /// <summary>
        /// Deletes specified domain.
        /// </summary>
        /// <param name="domainID">Domain ID. Use <see cref="IMailServerApi.GetDomains">GetDomains()</see> to get valid values.</param>
        /// <remarks>Deletes specified domain and all domain related data (users,mailing lists,routes).</remarks>
        public void DeleteDomain(string domainID)
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_DeleteDomain")){
                sqlCmd.AddParameter("_domainID" ,NpgsqlDbType.Varchar,domainID);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Gets all folders IMAP acl entries.
        /// </summary>
        /// <returns></returns>
        private DataSet GetACL()
        {
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"select * from lsIMAP_ACL")){
                DataSet ds = sqlCmd.Execute();
                ds.Tables[0].TableName = "ACL";

                return ds;
            }
        }
        /// <summary>
        /// Deletes IMAP folder.
        /// </summary>
        /// <param name="accessingUser">User who accesses this method. 
        /// User needs r permission to call this method or Exception is thrown. 
        /// There is special user 'system' for which permission check is skipped.</param>
        /// <param name="folderOwnerUser">User who's folder it is.</param>
        /// <param name="folder">Folder what to delete. For example: Inbox,Public Folders/Documnets .</param>
        public void DeleteFolder(string accessingUser,string folderOwnerUser,string folder)
        {
            /* Implementation notes:
                *) Validate values. Throw ArgumnetExcetion if invalid values.
                *) Ensure that user exists.
                *) Normalize folder. Remove '/' from folder start and end, ... .
                *) Do Shared Folders mapping.
                *) Don't allow to delete shared folders root folder.
                   For BoundedUser root don't allow root folder only,
                   for UsersShared root don't allow root + user name.
                *) Ensure that folder exists. Throw Exception if don't.
                *) See if user has sufficient permissions. User requires 'c' permission.
                   There is builtin user system, skip ACL for it.
                *) Create folder.
            */

            // Don't allow to delete inbox
            if(folder.ToLower() == "inbox"){
                throw new Exception("Can't delete inbox");
            }

            //--- Validate values -------------------//
            ArgsValidator.ValidateUserName(folderOwnerUser);
            ArgsValidator.ValidateFolder(folder);
            //---------------------------------------//

            // Ensure that user exists.
            if(!UserExists(folderOwnerUser)){
                throw new Exception("User '" + folderOwnerUser + "' doesn't exist !");
            }

            // Normalize folder. Remove '/' from folder start and end.
            folder = API_Utlis.NormalizeFolder(folder);

            // Do Shared Folders mapping.
            string originalFolder = folder;
            SharedFolderMapInfo mappedFolder = MapSharedFolder(originalFolder);
            if(mappedFolder.IsSharedFolder){
                folderOwnerUser = mappedFolder.FolderOnwer;
                folder = mappedFolder.Folder;

                /* Don't allow to delete shared folders root folder.
                   For BoundedUser root don't allow root folder only,
                   for UsersShared root don't allow root + user name.
                */

                // Main shared folder root.
                if(mappedFolder.SharedRootName.ToLower() == originalFolder.ToLower()){
                    throw new ArgumentException("Can't delete shared root folder '" + originalFolder + "' !");
                }
                // Users shared folder: root/username -> no folder
                if(folder == ""){
                    throw new ArgumentException("Can't delete shared root folder '" + originalFolder + "' !");
                }

                if(folderOwnerUser == "" || folder == ""){
                    throw new ArgumentException("Specified root folder '" + originalFolder + "' isn't accessible !");
                }
            }

            // Ensure that folder doesn't exists. Throw Exception if don't.
            if(!FolderExists(folderOwnerUser + "/" + folder)){
                throw new Exception("Folder '" + folder + "' doesn't exist !");
            }

            // See if user has sufficient permissions. User requires 'c' permission.
            //  There is builtin user system, skip ACL for it.
            if(accessingUser.ToLower() != "system"){
                IMAP_ACL_Flags acl = GetUserACL(folderOwnerUser,folder,accessingUser);
                if((acl & IMAP_ACL_Flags.c) == 0){
                    throw new InsufficientPermissionsException("Insufficient permissions for folder '" + accessingUser + "/" + folder + "' !");
                }
            }

            //--- Recycle bin handling ----------------------------------------------------------------------//
            if(Convert.ToBoolean(GetRecycleBinSettings().Rows[0]["DeleteToRecycleBin"])){
                IMAP_MessageCollection messages = new IMAP_MessageCollection();
                GetMessagesInfo("system",folderOwnerUser,folder,messages);
                foreach(IMAP_Message message in messages){
                    EmailMessageItems msgItems = new EmailMessageItems(message.ID,IMAP_MessageItems_enum.Message);
                    GetMessageItems("system",folderOwnerUser,folder,msgItems);
                    if(msgItems.MessageExists){
                        string subject = "<none>";
                        try{
                            subject = MimeUtils.ParseHeaderField("Subject:",msgItems.MessageStream);
                            subject = subject.Replace("\r","");
                            subject = subject.Replace("\n","");
                        }
                        catch{
                        }
                        msgItems.MessageStream.Position = 0;
                        byte[] data = new byte[msgItems.MessageStream.Length];
                        msgItems.MessageStream.Read(data,0,data.Length);

                        using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_StoreRecycleBinMessage")){
                            sqlCmd.AddParameter("_messageID" ,NpgsqlDbType.Varchar,Guid.NewGuid().ToString());
                            sqlCmd.AddParameter("_user"      ,NpgsqlDbType.Varchar,folderOwnerUser);
                            sqlCmd.AddParameter("_folder"    ,NpgsqlDbType.Varchar,folder);
                            sqlCmd.AddParameter("_subject"   ,NpgsqlDbType.Varchar,subject);
                            sqlCmd.AddParameter("_data"      ,NpgsqlDbType.Bytea  ,data);

                            DataSet ds = sqlCmd.Execute();
                        }
                    }
                }
            }
            //----------------------------------------------------------------------------------------------//

            //--- Delete folder
            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_DeleteFolder")){
                sqlCmd.AddParameter("_folderOwnerUser",NpgsqlDbType.Varchar,folderOwnerUser);
                sqlCmd.AddParameter("_folderName"     ,NpgsqlDbType.Varchar,folder);

                DataSet ds = sqlCmd.Execute();
            }
        }
        /// <summary>
        /// Stores message to specified folder.
        /// </summary>
        /// <param name="accessingUser">User who accesses this method. 
        /// User needs r permission to call this method or Exception is thrown. 
        /// There is special user 'system' for which permission check is skipped.</param>
        /// <param name="folderOwnerUser">User who's folder it is.</param>
        /// <param name="folder">Folder where to store message. For example: Inbox,Public Folders/Documnets .</param>
        /// <param name="msgStream">Stream where message has stored. Stream position must be at the beginning of the message.</param>
        /// <param name="date">Recieve date.</param>
        /// <param name="flags">Message flags.</param>
        public void StoreMessage(string accessingUser,string folderOwnerUser,string folder,Stream msgStream,DateTime date,IMAP_MessageFlags flags)
        {
            /* Implementation notes:
                *) Validate values. Throw ArgumnetExcetion if invalid values.
                *) Ensure that user exists.
                *) Normalize folder. Remove '/' from folder start and end, ... .
                *) Do Shared Folders mapping.
                *) Ensure that folder exists. Throw Exception if don't.
                *) See if user has sufficient permissions. User requires 'p' or 'i' permission.
                    There is builtin user system, skip ACL for it.
                *) Store message.
            */

            //--- Validate values -------------------//
            ArgsValidator.ValidateUserName(folderOwnerUser);
            ArgsValidator.ValidateFolder(folder);
            ArgsValidator.ValidateNotNull(msgStream);
            //---------------------------------------//

            // Ensure that user exists.
            if(!UserExists(folderOwnerUser)){
                throw new Exception("User '" + folderOwnerUser + "' doesn't exist !");
            }

            // Normalize folder. Remove '/' from folder start and end.
            folder = API_Utlis.NormalizeFolder(folder);

            // Do Shared Folders mapping.
            string originalFolder = folder;
            SharedFolderMapInfo mappedFolder = MapSharedFolder(originalFolder);
            if(mappedFolder.IsSharedFolder){
                folderOwnerUser = mappedFolder.FolderOnwer;
                folder = mappedFolder.Folder;

                if(folderOwnerUser == "" || folder == ""){
                    throw new ArgumentException("Specified root folder '" + originalFolder + "' isn't accessible !");
                }
            }

            // Ensure that folder exists. Throw Exception if don't.
            if(!FolderExists(folderOwnerUser + "/" + folder)){
                throw new Exception("Folder '" + folder + "' doesn't exist !");
            }

            // See if user has sufficient permissions. User requires 'p' or 'i' permission.
            //  There is builtin user system, skip ACL for it.
            if(accessingUser.ToLower() != "system"){
                IMAP_ACL_Flags acl = GetUserACL(folderOwnerUser,folder,accessingUser);
                if((acl & IMAP_ACL_Flags.p) == 0 && (acl & IMAP_ACL_Flags.i) == 0){
                    throw new InsufficientPermissionsException("Insufficient permissions for folder '" + accessingUser + "/" + folder + "' !");
                }
            }

            //--- Store message
            byte[] topLines = GetTopLines(msgStream,50);
            msgStream.Position = 0;
            byte[] messageData = new byte[msgStream.Length];
            msgStream.Read(messageData,0,messageData.Length);
            Mime m = null;
            try{
                msgStream.Position = 0;
                m = Mime.Parse(msgStream);
            }
            catch(Exception x){
                m = LumiSoft.Net.Mime.Mime.CreateSimple(new AddressList(),new AddressList(),"[BAD MESSAGE] Bad message, message parsing failed !","NOTE: Bad message, message parsing failed !\r\n\r\n" + x.Message,"");
            }
            byte[] envelope = System.Text.Encoding.Default.GetBytes(IMAP_Envelope.ConstructEnvelope(m.MainEntity));
            byte[] body     = System.Text.Encoding.Default.GetBytes(IMAP_BODY.ConstructBodyStructure(m,false));

            using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_StoreMessage")){
                sqlCmd.AddParameter("_userName"     ,NpgsqlDbType.Varchar   ,folderOwnerUser);
                sqlCmd.AddParameter("_folder"       ,NpgsqlDbType.Varchar   ,folder);
                sqlCmd.AddParameter("_messageID"    ,NpgsqlDbType.Varchar   ,Guid.NewGuid().ToString());
                sqlCmd.AddParameter("_size"         ,NpgsqlDbType.Integer   ,msgStream.Length);
                sqlCmd.AddParameter("_messageFlags" ,NpgsqlDbType.Integer   ,(int)flags);
                sqlCmd.AddParameter("_date"         ,NpgsqlDbType.Timestamp ,date);
                sqlCmd.AddParameter("_topLines"     ,NpgsqlDbType.Bytea     ,topLines);
                sqlCmd.AddParameter("_data"         ,NpgsqlDbType.Bytea     ,messageData);
                sqlCmd.AddParameter("_imapEnvelope" ,NpgsqlDbType.Bytea     ,envelope);
                sqlCmd.AddParameter("_imapBody"     ,NpgsqlDbType.Bytea     ,body);

                DataSet ds = sqlCmd.Execute();
            }
        }